指针与地址
地址也称内存地址。
概念:
在计算机中,所有的运行数据都存放在内存储器中,内存储器的一个字节占用一个内存单元。为方便访问这些内存单元,我们为每个内存单元进行了编号,这些编号就称为内存地址。
我们简单理解为:内存储器为一个酒店,内存单元是住客们,内存地址就相当于他们所住房间的门牌号。
例如:使用取地址运算符&时,就是在获取变量的内存地址
指针
概念:
根据内存地址就可以找到相应的内存单元,所以通常也把地址称为指针。
看下面的代码:
#include <stdio.h> int main() { int n; int *p = &n; printf("%p\n", p); return 0; }
其运行结果为: 0032F824
该结果即是变量n的内存地址,也称为其指针。
指针变量
概念:
在C语言中,允许用一个变量来存放指针,这种变量就称为指针变量。
其与一般变量一样,要先声明后使用
定义形式:
类型说明符(数据类型) * 指针变量名;
其中类型说明符表示该指针变量所指向的变量是什么数据类型,* 是指说明符,当*单独使用时,则为解引用操作符。
例如:
#include <stdio.h> int main() { int n = 5; int *p = &n; printf("%d\n", *p); //此处对P进行解引用操作,通过p的地址找到变量n return 0; }
运行结果为: 5
需要注意一点的是:* 是单目运算符,结合性为“左结合”,后面只能接指针变量。
指针与数组
指针与一维数组
指向一维数组元素的指针
如果定义了一个一维数组,此时再定义一个指针,并把数组的第一个元素的起始地址赋值给该指针,则该指针就指向了这个一维数组。
例如:
#include <stdio.h> int main() { int arr[5] = { 1,2,3,4,5 },i; int *p; p = &arr[0]; for (i = 0; i < 5; i++) { printf("arr[%d] = %d\n", i, *(p + i)); } return 0; }
其运行结果为:
指针p与一维数组arr的关系
指针与整数的加减运算
当指针指向数组元素后,加上或减去一个整数n,表示把指针的当前位置(指向某数组元素)向后或向前移动n个元素的位置。
例如:
#include <stdio.h> int main() { int arr1[5] = { 1,2,3,4,5 }; float arr2[5] = { 1.0,2.0,3.0,4.0,5.0 }; int *p; float *b; p = &arr1[0]; b = &arr2[0]; printf("指针加整数前\n%d\n%.2f\n", *p, *b); printf("\n"); p += 3; b += 4; printf("指针加整数后\n%d\n%.2f\n", *p, *b); return 0; }
其运行结果为:
指针的增量运算
指向数组元素的指针变量的值可以改变。如p++是合法的,使得p指向下一个数组元素。而arr++是非法的,因为arr是数组的首地址,是一个常量。
例如:
#include <stdio.h> int main() { int arr[5] = { 1,2,3,4,5 },*p; p = &arr[0]; printf("增量运算前\n%d\n", *p); p++; //或者++p; //此时指针在原来的基础上加上了4(查阅资料,根据VC++6.0编译环境int型数据占4个字节) //从而使得指针指向数组的下一个元素 printf("\n"); printf("增量运算后\n%d\n", *p); return 0; }
其运行结果为:
指针与指针的减法运算
当两个指针指向同一片连续的存储单元时,指针的减法运算的结果是一个整数,其值为这两个指针变量中的地址之差除以数据类型的长度。
例如:
#include <stdio.h> int main() { //建立一维数组和两个指针变量 float arr[5] = { 1.0,5.0,2.0,6.0,9.0 },*p,*b; p = &arr[4]; b = &arr[1]; //计算float型数据占多少个字节 printf("float型数据占%d个字节\n\n", sizeof(arr[0])); //打印出p和b的地址,不难算出(16进制转10进制来计算)相减之后结果为12 printf("p中存放的地址:%p\nb中存放的地址:%p\n两个地址相减得到结果为12\n\n", p, b); //打印出两个指针相减的结果 printf("两个指针相减的结果为:%d\n(12 / 4)", p - b); return 0; }
其运行结果为:
指针与指针的关系运算
当两个指针指向同一片连续的存储单元时,两个指针可以进行关系运算,即表示它们之间的位置关系。
int arr[10],*p,*b; p == b; //表示判断p和b是否指向同一数组元素 p > b; //表示判断p所指元素是否在b所指元素的后面 p < b; //表示判断p所指元素是否在b所指元素的前面
用这一知识点,将数组arr中n个整数按相反的顺序存放
#include <stdio.h> #define N 5 int main() { int arr[N], i, tmp, * p, * q; printf("请随机输入%d个数字\n", N); for (i = 0; i < N; i++) { printf("第%d个:", i + 1); scanf("%d", &arr[i]); } p = arr; //p指向数组中的第一个元素 q = arr + (N - 1); //q指向数组中的最后一个元素 while (p < q) //逆序存放数组中的元素 { tmp = *p; *p = *q; *q = tmp; p++; q--; } printf("逆序输出为:"); for (i = 0; i < N; i++) printf("%d ", arr[i]); printf("\n"); return 0; }
其运行结果为:
指针与二维数组
二维数组的元素及地址
定义一个二维数组int arr[ 3 ][ 4 ];表示二维数组有3行4列共12个元素,在内存中按行存放。
二维数组arr也可以理解为由3个元素组成,即arr[ 0 ]、arr[ 1 ]、arr[ 2 ],而每个元素是一个一维数组,且都包含了4个元素。
二维数组在内存中的存储方式示意图
通过行指针引用二维数组的元素
行指针
行指针是一种特殊的指针,它专门用于指向一维数组,定义行指针的一般形式如下:
类型说明符(* 指针名) [常量表达式];
其中,类型说明符代表行指针所指一维数组的元素类型,指针名与前面的指针说明*必须用括号括起来,常量表达式是指针所指向的一维数组的长度。
例如:
int arr[3][4]; int (*p)[4] = &arr[0]; //也可以写成int (*p)[4] = arr;
上面语句中定义了一个指向一维数组的指针p,指向包含4个int型元素的一维数组arr[ 0 ]。此时p + 1指向下一个一维数组arr[ 1 ],因此,*(p + 1)+ 2是arr[ 1 ][ 2 ]的地址,那么
*(*(p + 1)+ 2)就是二维数组元素arr[ 1 ][ 2 ]的值
故,以下几种方式都可以表示二维数组元素arr[ i ][ j ].
int arr[3][4], i , j ; int (*p)[4] = &arr[0]; //二维数组arr,arr首元素的地址p * (*(arr + i) + j); * (*(p + i) + j); p[i][j];
通过列指针引用二维数组的元素
当指针p指向二维数组的首元素之后,p + 1将指向二维数组的第二个元素,p + 2将指向二维数组的第三个元素,以此类推
例如:
#include <stdio.h> int main() { int arr[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} }; int *p = &arr[0][0]; printf("%d\n", *p); printf("%d\n", *(p + 1)); return 0; }
其运行结果为:
用指针法输入输出二维数组中的各个元素:
//行指针法 #include <stdio.h> int main() { int arr[3][4], i, j; int (*ptr) [4] = &arr[0]; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { scanf("%d", *(ptr + i) + j); } } printf("\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { printf("%d\t", *(*(ptr + i) + j)); } printf("\n"); } return 0; }
//列指针法 #include <stdio.h> int main() { int arr[3][4],i,j; int *p = &arr[0][0]; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { scanf("%d", p+i+j); } } printf("\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { printf("%d\t", *(p + i + j)); } printf("\n"); } return 0; }
以上运行结果都为:
指针与字符数组
字符数组在C语言中可以用字符串常量初始化,也可以整串地输入或输出。
由于指针与数组的等价性,字符指针也有如下特点:
C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)二:https://developer.aliyun.com/article/1530355