指针详解(C语言)
一、指针指向基本类型变量
在C语言中,基本类型由char, short, int, long, float, double这六个基本类型组成,注意数组类型不是基本类型。基本类型指针的用法,比如 char *p = 'A'; ,这在编译过程中,不会报错。而在运行之后会出现异常。原因是指针类型只能指向地址,而不是一个常量,字符'A'是一个常量。修改以上代码如下 char ch = 'A', *p = &ch; 。先定义一个字符类型变量ch,赋值为'A',然后用指针指向ch的地址,这样就可以直接用*p打印字符'A'。
1 char ch = 'A', *p = &ch; 2 char *p2 = "大哥哥"; // 字符串可以直接赋值,因为字符串在常量区申请了一块内存空间 3 4 printf("%c", *p); // A 5 printf("%s", p2); // 大哥哥
我们也可以通过对指针p来对ch进行修改
1 *p = 'B'; 2 printf("%c\n", ch); // B
二、字符指针和字符数组的区别
1 #include <stdio.h> 2 #include <string.h> 3 4 int main() 5 { 6 char *p = "字符指针"; 7 char arr[] = "字符数组"; // 字符指针和字符数组初始化 8 p = "字符指针 -- 2"; // 字符指针可以在定义之后重新指向另一个字符串 9 10 // arr = "大哥哥"; // 修改失败 11 strcpy(arr, "字符数组 -- 2"); // 修改成功,但是却导致了字符指针p值为空了 12 13 printf("%d\n", *p == NULL); // 1 14 15 printf("%s\n", p); // "" 16 printf("%s\n", arr); // "字符数组 -- 2" 17 18 return 0; 19 }
三、指针作为函数参数
1 #include <stdio.h> 2 3 // 交换两个变量的值 4 void swap(int *x, int *y) 5 { 6 int temp; 7 temp = *x; 8 *x = *y; 9 *y = temp; 10 } 11 12 int main() 13 { 14 int a = 10, b = 5; 15 int *pa = &a, *pb = &b; 16 17 // swap(&a, &b); // 第一种方式 18 swap(pa, pb); // 第二种方式 19 printf("a=%d\tb=%d\n", a, b); // a=5 b=10 20 }
swap()函数需要传入两个变量的地址,并交换两个变量的值。在main函数中,定义了两个变量,a和b,它们值分别为10和5。通过第一种方式,我们需要将a和b的地址作为实参传入swap()方法中,来实现a和b的值交换。第二种方法,通过指针pa和pb指向了a和b,并将pa和pb传入swap函数中。
指针pa相当于&a,pa是指向变量a的地址。*pa是a的值(10),&pa表示指针自己本身的地址,可以通过二级指针来指向一级指针的地址来对一级指针所指向的变量进行操作。
四、一级指针和二级指针
1 #include <stdio.h> 2 3 // 交换两个变量的值 4 void swap(int *x, int *y) 5 { 6 int temp; 7 temp = *x; 8 *x = *y; 9 *y = temp; 10 } 11 12 int main() 13 { 14 int a = 10, b = 5; 15 int *pa = &a, *pb = &b; 16 17 int **ppa = &pa, **ppb = &pb; // 加了两个二级指针来指向pa和pb自己的地址 18 swap(*ppa, *ppb); // *ppa和*ppb指向了pa和pb指向的变量a和b的地址 19 20 printf("a=%d\tb=%d\n", a, b); 21 printf("%d\n", **ppa); // 5 22 }
17行定义了两个二级指针ppa和ppb,分别指向了一级指针pa和pb的自身地址。注意pa和pb自身的地址和他们指向的地址不一样,指针在内存中也是有空间的,32位操作系统默认占4字节,64位8字节。如指针pa的地址用&pa表示,它所指向的地址直接用pa表示,它所指向地址的值用*pa表示。
二级指针的定义就是比一级指针多了个 * 号罢了。如ppa指向pa的地址,*ppa指向pa所指向的地址,**ppa表示pa指向地址的值,和*pa等价。多级指针用法不外乎和这一个道理。
1 void swap(int **x, int **y) 2 { 3 int temp; 4 temp = **x; 5 **x = **y; 6 **y = temp; 7 }
在调用swap函数时,直接传入ppa和ppb就行了。如 swap(ppa, ppb); 。来完成对变量a和b值的交换。
五、数组指针和指针数组
1 #include <stdio.h> 2 3 int main() 4 { 5 int arr[5] = {8, 6, 4, 1, 4}; // 定义一个长度为5的int类型数组 6 int *pArr = arr; 7 int i; 8 9 *pArr = 10; // 将数组中第一个元素修改成10 10 *(pArr+2) = 13; // 将数组中第3个元素修改成13 11 12 for (i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) 13 { 14 printf("%d\t", *(pArr+i)); // 10 6 13 1 4 15 } 16 17 return 0; 18 }
1 int arr[2][5] = {...}; // 赋值简写 2 int (*pArr)[5] = arr; // 指向二维数组,这里必须用()将指针包起来,来定义数组指针。否则就变成指针数组了 3 4 int arrArr[4][2][5] = {...}; 5 int (*pArr)[2][5] = arrArr; // 指向三维数组,除了第一个[]不用写
在定义数组指针时,有一个小坑。如果不将指针部分用 () 起来,那么定义的就不是数组指针了,而是指针数组。由于 [] 优先级比 * 高,则p会先和 [] 组成一队,然后与 * 相连,那么这将定义一个全是由指针组成的数组。
指针数组的用法:
1 #include <stdio.h> 2 3 int main() 4 { 5 int arr[5] = {8, 6, 4, 1, 4}; // 定义一个长度为5的int类型数组 6 int *pArr[5]; 7 int i; 8 9 for (i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) 10 { 11 pArr[i] = &arr[i]; // 将数组中每个元素依次对应指针数组中的每个指针 12 } 13 14 *pArr[0] = 10; // 将数组中第一个元素修改成10 15 *pArr[2] = 13; // 将数组中第3个元素修改成13 16 17 for (i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) 18 { 19 printf("%d\t", *pArr[i]); // 10 6 13 1 4 20 } 21 22 return 0; 23 }
六、常量指针和指针常量
指针常量无法修改自己已经指向的地址,但可以修改所指向地址的值。
1 int a,b; 2 int * const p=&a //指针常量 3 //那么分为一下两种操作 4 *p=9;//操作成功 5 p=&b;//操作错误
1 int a,b; 2 const int *p=&a //常量指针 3 //那么分为一下两种操作 4 *p=9;//操作错误 5 p=&b;//操作成功
指向常量的指针常量既无法修改自己指向的地址,也无法修改自己所指向地址的值。
1 const int * const b = &a;//指向常量的指针常量