c语言指针
以下讲解是按照如下这个程序的执行顺序来讲解的
1 int a,b; //这是一个普通的整型变量 2 int *p;//这是一个整形的指针 3 a = 3; 4 b = 4; 5 6 7 printf(" a的地址:%d;\r\n", &a); 8 printf(" b的地址:%d;\r\n", &b); 9 printf(" p的地址:%d;\r\n", &p); 10 printf(" p的值:%d,现在p的值是不确定的,目前只是为p申请了地址,还没有为它赋值;\r\n", p); 11 12 p = &a;//取址运算/* p现在指向a */ 13 printf(" 利用取址操作p = &a;,把a的地址赋值给p,现在p的值是%d,也就是a的地址;\r\n", p); 14 printf(" p的地址没有变化,p的地址仍然是%d,在这个地址上存储的是变量a的地址;\r\n", &p); 15 16 printf(" 利用*运算符得到指针p指向地址中的数值为%d,在刚才p已经指向变量a的地址了,所以指针p指向地址中的值是3,但是p的值仍然是a的地址;\r\n", *p); 17 18 b = *p;/* b现在为a的值 */ 19 printf(" b = *p;,现在b的值就是p指向地址中的值,也就是a的值:%d;\r\n", b); 20 21 *p = 5;/* a现在为5 */ 22 printf(" 现在利用*p为p指向地址中存储的值进行赋值:%d,这时a的值也已经改变了:%d;\r\n", *p,a);
先做如下定义并把详细信息打印出来
1 int a,b; //这是一个普通的整型变量 2 int *p;//这是一个整形的指针 3 a = 3; 4 b = 4; 5 6 printf(" a的地址:%d;\r\n", &a); 7 printf(" b的地址:%d;\r\n", &b); 8 printf(" p的地址:%d;\r\n", &p); 9 printf(" p的值:%d,现在p的值是不确定的,目前只是为p申请了地址,还没有为它赋值;\r\n", p);
指针p定义的时候没有进行初始化,所以在这里,p的初始值是不确定的。
当然也可以在p定义的时候赋初值,这样p的初始值就是确定的了。
1 p = 1;
一元运算符&可用于取一个对象的地址,如下,这时p为指向a的指针。地址运算符&只能应用于内存中的对象,即变量与数组元素。它不能作用于表达式、常量或register类型的变量。
这时p的值是3930420,即变量a的地址;
利用&取出p的地址仍然为3930396,没有变;
利用间接寻址*,*p可以得到指针p指向地址中的值为3,即a的值。
1 p = &a;//取址运算/* p现在指向a */ 2 printf(" 利用取址操作p = &a;,把a的地址赋值给p,现在p的值是%d,也就是a的地址;\r\n", p); 3 printf(" p的地址没有变化,p的地址仍然是%d,在这个地址上存储的是变量a的地址;\r\n", &p); 4 5 printf(" 利用*运算符得到指针p指向地址中的数值为%d,在刚才p已经指向变量a的地址了,所以指针p指向地址中的值是3,但是p的值仍然是a的地址;\r\n", *p); 6
利用*可以得到p地址中的数值,这里b的值就是3,即a的值。
1 b = *p;/* b现在为a的值 */ 2 printf(" b = *p;,现在b的值就是p指向地址中的值,也就是a的值:%d;\r\n", b);
对*p进行赋值后,也就是对p指针指向地址中的数值进行赋值,这是a的值也就变为了5
*p = 5;/* a现在为5 */ printf(" 现在利用*p为p指向地址中存储的值进行赋值:%d,这时a的值也已经改变了:%d;\r\n", *p,a);
图解C语言指针
定义两个变量
1 int a=3,b; //这是一个普通的整型变量 2 int *p;//这是一个整形的指针
定义后,a的地址是0x2000,p的地址是0x3000;
在定义的时候a赋的初始值是3,p没有赋初始值,所以p的值是不确定的。
现在进行运算:
1 p = &a;//取址运算/* p现在指向a */
这时内存图就变成了这样,p的地址没有变化,但是p的值变化了,此时,*p=3;
指针与函数
指针作为函数的形参
在程序设计中,指针作为函数形参往往会带来意想不到的效果,下面用一个例程来讲解指针作为函数形参的特性。
例子:用一个函数交换两个变量的值:
1 void Swap(int x, int y) 2 { 3 int temp = 0; 4 temp = x; 5 x = y; 6 y = temp; 7 } 8 9 void Swap_pointer(int *x, int *y) 10 { 11 int temp = 0; 12 temp = *x; 13 *x = *y; 14 *y = temp; 15 } 16 17 /* 18 指针与函数 19 2019-05-09 20 */ 21 void Test2() 22 { 23 int a = 1, b = 2; 24 Swap(a, b); 25 printf("a=%d\r\n", a); 26 printf("b=%d\r\n", b); 27 Swap_pointer(&a, &b); 28 printf("\r\n"); 29 printf("a=%d\r\n", a); 30 printf("b=%d\r\n", b); 31 }
执行结果如下图,可以明显的看出指针作为函数形参的特性。
具体讲解详见《C语言程序设计》的5.2章节。
指针与数组
使用数组时,需要明白的一些事项:
1,申请的数组存储在相邻的内存区域中;
2,数组名所代表的就是该数组最开始的一个元素的地址;
3,对数组元素a[i]的引用也可以写成*(a+i)这种形式;
4,&a[i]和a+i的含义是相同的,简而言之,一个通过数组和下标实现的表达式可等价地通过指针和偏移量实现。;
5,数组名不是变量,因此,类似于a=pa和a++形式的语句是非法的;
6,当把数组名传递给一个函数时,实际上传递的是该数组第一个元索的地址;
下面通过一些例程来解释指针与数组的运用:
1 /* 2 统计字符串长度 3 2019-05-09 4 */ 5 //int StrLen(char *s)//数组作为形参有两种写法“char s[]”、“char *s”,效果一样的 6 int StrLen(char s[]) 7 { 8 int n; 9 for (n = 0; *s != '\0'; s++) 10 n++; 11 return n; 12 } 13 14 /* 15 2019-05-09 16 */ 17 void Array_pointe