qidao123.com技术社区-IT企服评测·应用市场

标题: 指针与数组 [打印本页]

作者: 花瓣小跑    时间: 2025-4-19 19:24
标题: 指针与数组
指针与数组

指针操作数组元素

在C语言中,数组名现实上就是一个指向数组首元素的指针。换句话说,可以把数组名视为指向了数组的第一个元素的内存所在。
例如,对于一个整型数组 int arry[5] = {1, 2, 3, 4, 5},我们可以通过数组名 arry 大概通过取指针操作符 &arry[0] 来获取指向数组第一个元素的指针。数组名字是数组的首元素所在,但它是一个常量。
我们可以通过指针访问数组元素大概遍历整个数组。
  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int num1 = 10;
  5.     int num2 = 20;
  6.     int num3 = 30;
  7.     // 声明指针数组,存储指向 int 类型数据的指针
  8.     int* arr[3];
  9.     int **p = arr;
  10.     arr[0] = &num1;  // 将指针指向变量 num1
  11.     arr[1] = &num2;  // 将指针指向变量 num2
  12.     arr[2] = &num3;  // 将指针指向变量 num3
  13.     // 指针数组:存储3个char类型指针
  14.     char *str_array[3] = {"Hello", "World", "C"};
  15.     // 通过指针数组访问存储的指针并输出对应的值
  16.     for (int i = 0; i < 3; i++)
  17.     {
  18.         printf("*arr[%d]:%d, **p:%d\n", i, *arr[i], **p);
  19.         p++;
  20.         printf("*str_array[%d]:%s\n", i, str_array[i]);
  21.         printf("*str_array[%d]:%d\n", i, *str_array[i]);//字符串首字符的ASCII数值
  22.     }
  23.     return 0;
  24. }
  25. /*输出结果:
  26. *prt=1, *arr=1
  27. *(ptr + 2))=3
  28. arr[1])=10
  29. *prt=1
  30. ptr:0x7fff864c8004, arr:0x7fff864c8000
  31. *prt=10
  32. ptr:0x7fff864c8008, arr:0x7fff864c8000
  33. *prt=3
  34. ptr:0x7fff864c800c, arr:0x7fff864c8000
  35. *prt=4
  36. ptr:0x7fff864c8010, arr:0x7fff864c8000
  37. *prt=5
  38. ptr:0x7fff864c8014, arr:0x7fff864c8000
  39. address between prt and arr is 5
  40. */
复制代码
指针加减法

指针加减法答应我们将指针与一个整数相加/相减。加法/减法运算将根据指针所指向的数据类型来调解指针的位置。
如果是一个int,+1/-1的结果是增加/减少一个int的大小。
如果是一个char
,+1/-1的结果是增加/减少一个char大小。
对于数组而言,可以通过指针加减法对其进行遍历。
指针与指针相减

  1. #include <stdio.h>
  2. #include <stddef.h>
  3. int main()
  4. {
  5.     //数组元素距离
  6.     int arr[5] = {1,2,3,4,5};
  7.     int *start = &arr[0], *end = &arr[4];
  8.     ptrdiff_t element_diff = end - start; //4,字符差
  9.     ptrdiff_t byte_diff = (char*)end - (char*)start;//16,字节差
  10.     printf("element_diff:%ld, byte_diff:%ld\n", element_diff, byte_diff);
  11.     //字符串字符差
  12.     char str[] = "Hello";
  13.     char *p = str;
  14.     while (*p) p++;
  15.     ptrdiff_t char_diff = p - str;//5,字符差,这里本质是一个char arr[]
  16.     printf("char_diff:%ld\n", char_diff);
  17.     int Data[3][4];
  18.     int (*p1)[4] = Data;     // 行指针,指向第一行
  19.     int (*p2)[4] = Data + 2; // 行指针,指向第三行
  20.     ptrdiff_t row_diff = p2 - p1; // 2(行数差)
  21.     printf("row_diff:%ld\n", row_diff);
  22. }
  23. /*
  24. 测试结果:
  25. element_diff:4, byte_diff:16
  26. char_diff:5
  27. row_diff:2
  28. */
复制代码
  1. struct S { int a; double b; };
  2. size_t offset = offsetof(struct S, b); // 正确获取偏移量
复制代码
指针数组和数组指针

指针数组

  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int num1 = 10;
  5.     int num2 = 20;
  6.     int num3 = 30;
  7.     // 声明指针数组,存储指向 int 类型数据的指针
  8.     int* arr[3];
  9.     int **p = arr;
  10.     arr[0] = &num1;  // 将指针指向变量 num1
  11.     arr[1] = &num2;  // 将指针指向变量 num2
  12.     arr[2] = &num3;  // 将指针指向变量 num3
  13.     //指针数组:存储3个char类型指针
  14.     char *str_array[3] = {"Hello", "World", "C"};
  15.     // 通过指针数组访问存储的指针并输出对应的值
  16.     for (int i = 0; i < 3; i++)
  17.     {
  18.         printf("*arr[%d]:%d, **p:%d\n", i, *arr[i], **p);
  19.         p++;
  20.         printf("*str_array[%d]:%s\n", i, str_array[i]);
  21.         printf("*str_array[%d]:%d\n", i, *str_array[i]);//字符串首字符的ASCII数值
  22.     }
  23.     return 0;
  24. }
  25. /*运行结果:
  26. *arr[0]:10, **p:10
  27. *str_array[0]:Hello
  28. *str_array[0]:72
  29. *arr[1]:20, **p:20
  30. *str_array[1]:World
  31. *str_array[1]:87
  32. *arr[2]:30, **p:30
  33. *str_array[2]:C
  34. *str_array[2]:67
  35. */
复制代码
利用指针数组存储差别类型的数据

理论上,指针数组的确可以存储差别类型的数据,比如利用void*全能指针大概干脆存储布局体。但直接利用 void* 会绕过类型查抄,需程序员自行包管类型正确性,而且不加注释的话有点比较难维护。
  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int a = 1;
  5.     float b = 2.5;
  6.     char c = 'T';
  7.     // 声明指针数组,类型为void*
  8.     void* arr[3];  
  9.     arr[0] = &a;  
  10.     arr[1] = &b;  
  11.     arr[2] = &c;  
  12.     printf("arr[0]:%d\n", *(int*)arr[0]);
  13.     printf("arr[1]:%f\n", *(float*)arr[1]);
  14.     printf("arr[2]:%c\n", *(char*)arr[2]);
  15.     //测试程序,这里不考虑字节对齐了
  16.     typedef struct
  17.     {
  18.         int a;
  19.         float b;
  20.         char c;
  21.     }Data;
  22.     Data data1 = {.a = 1,.b=1.1,.c = 'a'};
  23.     Data data2 = {.a = 2,.b=2.2,.c = 'b'};
  24.     Data* arr_data[2] = {&data1, &data2};
  25.     printf("arr_data[0]:%f\n", arr_data[0]->b);
  26.     printf("arr_data[1]:%c\n", ar
  27. r_data[1]->c);
  28.     return 0;
  29. }
  30. /*
  31. 测试结果
  32. arr[0]:1
  33. arr[1]:2.500000
  34. arr[2]:T
  35. arr_data[0]:1.100000
  36. arr_data[1]:b
  37. */
复制代码
数组指针

  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int arr[3][4] =
  5.     {
  6.         {1, 2, 3, 4},
  7.         {5, 6, 7, 8},
  8.         {9, 10, 11, 12}
  9.     };
  10.     // 定义数组指针,指向含有4个int的数组(即一行)
  11.     int (*ptr)[4] = arr; // 指向第一行
  12.     for(int i = 0; i < 3; i++)
  13.     {
  14.         printf("ptr address:%p\n", ptr);
  15.         for(int j = 0; j < 4;j++)
  16.         {
  17.             printf("arr[0][%d]:%d, address:%p\n", j, (*ptr)[j], &(*ptr)[j]);
  18.         }   
  19.         ptr++;
  20.     }
  21. }
复制代码
总结

特性指针数组数组指针本质数组,元素是指针指针,指向整个数组声明int *arr[5];int (*arr)[5];内存占用5 * sizeof(int*)(如40字节)sizeof(int*)(如8字节)加减操作按指针大小移动(如8字节)按整个数组大小移动(如5*sizeof(int))典型用途字符串数组、动态多维数组的行管理二维数组的行操作、函数传参二维数组和指针

对于arr[j]表示的二维数组而言,可以用指针去表示:
其元素访问的方式如下:

  • 数组下标法:arr[j]
  • 指针表示法:*(*(arr + i) + j)
看下面的代码示例。本质上,二维数组是一个指向一维数组的指针,只是由于二维数组中内存是连续的,所以可以通过指针的加法来表示后面的几个一维数组。
  1. #include <stdio.h>
  2. int main() {
  3.     int arr[3][4] = {
  4.         {1, 2, 3, 4},
  5.         {5, 6, 7, 8},
  6.         {9, 10, 11, 12}
  7.     };
  8.    
  9.     //用数组指针表示一个一维数组
  10.     int (*ptr)[4] = arr;
  11.     for(int i = 0; i < 3; i++) {
  12.         for(int j = 0; j < 4; j++) {
  13.             printf("%d %d ", *(*(ptr + i) + j), *(*(arr + i) + j));
  14.             //以上两种结果一样,说明二维数组名不是二级指针,它是指向一维数组的指针
  15.         }
  16.         printf("\n");
  17.     }
  18.    
  19.     return 0;
  20. }
  21. /*
  22. 结果:
  23. 1 1 2 2 3 3 4 4
  24. 5 5 6 6 7 7 8 8
  25. 9 9 10 10 11 11 12 12
  26. */
复制代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4