当前位置:   article > 正文

C语言数组之指针数组和数组指针

指针数组

目录

前言

1、指针数组

1.1、指针数组的定义

1.2、指针数组详解

2、数组指针

2.1、数组指针的定义

2.2、数组指针详解

3、二维数组与数组指针

4、数组名和数组名取地址的区别

4、数组指针的应用

总结


前言

提示:这里可以添加本文要记录的大概内容:

本文主要介绍指针数组、数组指针、二维数组


1、指针数组

1.1、指针数组的定义

指针数组是多个指针变量,以数组的形式存储在内存中,数组中的每个元素都是一个地址,占有多个指针的存储空间。指针数组即存放指针的数组,如:char *array[5];含义是一个存放了5个指向字符型数据的指针的数组。

1.2、指针数组详解

  1. #includeint main(void)
  2. {
  3.     char **p, i;
  4.     char *strings[] ={"one", "two", "three"};
  5.     p = strings; //strings是地址的地址,所以要定义**p
  6.     for(i = 0; i < 3; i++)
  7.         printf("%s\n", *(p++)); //这里*(p++)是取出存储在数组中的每一个字符串的地址return 0;
  8. }
  9. //在string[0]存放字符串“one”的首字符的地址,
  10. //string[1]存放字符串“two”的首字符的地址,
  11. //string[3]存放字符串“three”的首字符的地址。
  12. /*****************************************/
  13. void func(char **p) {
  14.     char *t;
  15.     t = (p += 3)[-1];
  16.     printf("%s\n",*p);
  17.     printf("%s\n",t);
  18. }
  19. int main() {
  20.     int *arr[] = {"ab","ce","ef","gh","ij","kl"};//指针数组
  21.     func(arr);
  22.     return 0;
  23. }
  24. //输出
  25. //gh
  26. //ef

2、数组指针

2.1、数组指针的定义

数组指针是一个指针变量,占有内存中一个指针的存储空间;数组指针即指向数组的指针,如:char (*array)[5];含义是一个指向存放5个字符的数组的指针。

2.2、数组指针详解

数组指针的定义,如:int (*p)[3]; 首先()的优先级高,所以首先p 和*结合,说明 p是一个指针,然后int 和[3]都是修饰这个指针的,意思是,这个指针指向了一个里面有3个int型元素的数组。

  1. int main() {
  2.     int a[3] = {1,2,3};
  3.     int (*p)[3] = a;//compile warning: initialization from incompatible pointer type
  4.     printf("%p,%p,%p,%p,%d,%d\n",a,&a,p,*p,**p,*p[0]);
  5.     return 0;
  6. }
  7. //输出
  8. //0060FEF0,0060FEF0,0060FEF0,0060FEF0,1,1

分析:
p是一个指向数组的指针(这里的p只不过是指针变量的名字,说p指向一个数组,其实就是p变量保存了数组的首地址)那么,在上面的例子中我们把 a 数组的地址给了这个指针变量(注意:&a取得是整个数组的地址)所以p指向了这个数组,p的值是数组首字节的地址。

这里要注意的是*p的类型是int * 类型,为甚么呢?不是 *p应该是这个数组吗?这是因为在C语言中规定,数组“本身”出现在非sizeof,非 & 后面时,会自动转换为指向数组首元素的指针,也就是说,这里的*p转化为数组首元素的指针了(这个指针的值为第一个首元素第一个字节的地址,映射的是四个字节)。

在这个数组中的首元素的类型是int ,所以*p的类型就为int * ,所以 *p的值就和p的值相等了,**p的值就为第一个元素的值 1 ,而*p[0]则因为[]的优先级高,所以 p[0]就是数组首元素的地址,*p[0]就为数组首元素了。

  1. int main() {
  2. int a[5] = { 1, 2, 3, 4, 5 }; //步长为5的数组指针,即数组里有5个元素
  3. int (*p)[5];
  4. p = &a; //把数组a的地址赋给p,则p为数组a的地址,则*p表示数组a本身
  5. printf("%p\n", a); //输出数组a的地址,一般用数组的首元素地址来标识一个数组
  6. printf("%p\n", p); //p为数组a的地址
  7. printf("%p\n", *p); //*p表示数组a本身,一般用数组的首元素地址来标识一个数组
  8. printf("%p\n", &a[0]); //a[0]的地址
  9. printf("%p\n", &a[1]); //a[1]的地址
  10. printf("%p\n", p[0]); //数组首元素的地址
  11. printf("%d\n", **p); //*p表示地址,则*(*p)表示值,当*p表示数组首元素地址时,**p表示首元素本身,即首元素的值1
  12. printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1
  13. printf("%d\n", *p[1]); //错误,不表示a[1]...表示什么我还不知道
  14. int *p;
  15. p = a;
  16. printf("%c", *p++);
  17. printf("%c", p[1]); //利用数组形式输出printf("%c", *a++); //这里不能改变数组的地址,会报错printf("%c", *(p+1)); //没有改变数组地址,可行

3、二维数组与数组指针

  1. int main() {
  2.     int arr[][3] = {1,2,3,4,5,6};
  3.     int (*ptr)[3] = arr;
  4.     printf("%d,%d\n",(*ptr)[0],(*ptr)[1]);
  5.     ptr++;    //ptr = ptr + 1;ptr跨过了a[0][],指向了a[1][]
  6.     printf("%d,%d\n",(*ptr)[0],(*ptr)[1]);
  7.     return 0;
  8. }
  9. //输出
  10. //1,2
  11. //4,5

4、数组名和数组名取地址的区别

  1. int main() {
  2.     int a[10];
  3.     printf("a:/t%p/n", a);
  4.     printf("&a:/t%p/n", &a);
  5.     printf("a+1:/t%p/n", a+1);
  6.     printf("&a+1:/t%p/n", &a+1);
  7.     return 0;
  8. }
  9. //输出:
  10. //a:         0012FF20
  11. //&a:        0012FF20  
  12. //a+1:       0012FF24  
  13. /&a+1:       0012FF48

注意:
(1)、a(a+0)表示&a[0],也即对数组首元素取地址。数组名的值是个指针常量,也就是数组第一个元素的地址。 它的类型取决于数组元素的类型。
(2)、取一个数组名的地址(&a)所产生的是一个指向整个数组的指针,而不是一个指向某个指针常量的指针。所以&a后返回的指针便是指向整个数组的指针,跟a(一个指向a[0]的指针)在指针的类型上是有区别。
(3)、a和&a指向的是同一块地址,但他们+1后的效果不同,a+1是增加一个元素的内存大小(增加4字节)即&a[1],而&a+1增加的是整个数组的内存大小(增加40)。
(4)、当数组名作为sizeof操作符和单目操作符&的操作数时。 sizeof返回整个数组的长度,而不是指向数组的指针的长度。a+1表示首地址+sizeof(元素类型)。&a虽然值为数组首元素地址,但类型为:类型 (*)[数组元素个数],所以&a+1大小为:首地址+sizeof(a)。

4、数组指针、数组指针、二维数组的应用

若有定义语句:char s[3][10],(*k)[3],*p;,则如下赋值语句正确的是( )

A. p=s;
B. p=k;
C. p=s[0];
D. k=s;
正确答案:C

  1. #define TOUCHKEY_BT_SHORT \
  2. /*00*/ NO_MSG,\
  3. /*01*/ NO_MSG,\
  4. /*02*/ NO_MSG,\
  5. /*03*/ NO_MSG,\
  6. /*04*/ NO_MSG,\
  7. /*05*/ NO_MSG,\
  8. /*06*/ NO_MSG,\
  9. /*07*/ NO_MSG,\
  10. /*08*/ NO_MSG,\
  11. /*09*/ NO_MSG,
  12. #define TOUCHKEY_BT_LONG \
  13. /*00*/ NO_MSG,\
  14. /*01*/ NO_MSG,\
  15. /*02*/ NO_MSG,\
  16. /*03*/ NO_MSG,\
  17. /*04*/ NO_MSG,\
  18. /*05*/ NO_MSG,\
  19. /*06*/ NO_MSG,\
  20. /*07*/ NO_MSG,\
  21. /*08*/ NO_MSG,\
  22. /*09*/ NO_MSG,
  23. #define TOUCHKEY_BT_HOLD \
  24. /*00*/ NO_MSG,\
  25. /*01*/ NO_MSG,\
  26. /*02*/ NO_MSG,\
  27. /*03*/ NO_MSG,\
  28. /*04*/ NO_MSG,\
  29. /*05*/ NO_MSG,\
  30. /*06*/ NO_MSG,\
  31. /*07*/ NO_MSG,\
  32. /*08*/ NO_MSG,\
  33. /*09*/ NO_MSG,
  34. #define TOUCHKEY_BT_LONG_UP \
  35. /*00*/ NO_MSG,\
  36. /*01*/ NO_MSG,\
  37. /*02*/ NO_MSG,\
  38. /*03*/ NO_MSG,\
  39. /*04*/ NO_MSG,\
  40. /*05*/ NO_MSG,\
  41. /*06*/ NO_MSG,\
  42. /*07*/ NO_MSG,\
  43. /*08*/ NO_MSG,\
  44. /*09*/ NO_MSG,
  45. #define KEY_REG_AD_MAX (10)
  46. #define KEY_REG_IO_MAX (10)
  47. #define KEY_REG_IR_MAX (21)
  48. #define KEY_REG_TOUCH_MAX (10)
  49. #define KEY_REG_UART_MAX (10)
  50. const u16 task_bt_touch_table[4][KEY_REG_TOUCH_MAX] = {
  51. /*短按*/ {TOUCHKEY_BT_SHORT},
  52. /*长按*/ {TOUCHKEY_BT_LONG},
  53. /*连按*/ {TOUCHKEY_BT_HOLD},
  54. /*长按抬起*/ {TOUCHKEY_BT_LONG_UP},
  55. };
  56. typedef struct __KEY_REG {
  57. const u16(*_ad)[KEY_REG_AD_MAX];
  58. const u16(*_io)[KEY_REG_IO_MAX];
  59. const u16(*_ir)[KEY_REG_IR_MAX];
  60. const u16(*_touch)[KEY_REG_TOUCH_MAX];
  61. const u16(*_uart)[KEY_REG_UART_MAX];
  62. } KEY_REG;
  63. const KEY_REG task_bt_key = {
  64. ._ad = task_bt_ad_table,
  65. ._io = task_bt_io_table,
  66. ._ir = task_bt_ir_table,
  67. ._touch = task_bt_touch_table,
  68. ._uart = task_bt_io_table,//task_bt_touch_table,
  69. };
  70. typedef struct __TASK_APP {
  71. // const char *name;
  72. tbool(*skip_check)(void **priv);
  73. void *(*init)(void *priv);
  74. void (*exit)(void **priv);
  75. void (*task)(void *priv);
  76. const KEY_REG *key;
  77. } TASK_APP;
  78. const TASK_APP task_bt_hid_info = {
  79. .skip_check = NULL,
  80. .init = task_bt_hid_init,
  81. .exit = task_bt_exit,
  82. .task = task_bt_deal,
  83. .key = &task_bt_key,
  84. };


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/223560
推荐阅读
相关标签
  

闽ICP备14008679号