目录

前言

1、指针数组

1.1、指针数组的定义

1.2、指针数组详解

2、数组指针

2.1、数组指针的定义

2.2、数组指针详解

3、二维数组与数组指针

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

4、数组指针的应用

总结


前言

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

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


1、指针数组

1.1、指针数组的定义

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

1.2、指针数组详解

#includeint main(void){ char **p, i; char *strings[] ={"one", "two", "three"}; p = strings; //strings是地址的地址,所以要定义**p for(i = 0; i < 3; i++)printf("%s\n", *(p++)); //这里*(p++)是取出存储在数组中的每一个字符串的地址return 0;}//在string[0]存放字符串“one”的首字符的地址,//string[1]存放字符串“two”的首字符的地址,//string[3]存放字符串“three”的首字符的地址。/*****************************************/void func(char **p) {char *t;t = (p += 3)[-1];printf("%s\n",*p);printf("%s\n",t);}int main() {int *arr[] = {"ab","ce","ef","gh","ij","kl"};//指针数组func(arr);return 0;}//输出//gh//ef

2、数组指针

2.1、数组指针的定义

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

2.2、数组指针详解

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

int main(){int a[3] = {1,2,3};int (*p)[3] = a;//compile warning: initialization from incompatible pointer typeprintf("%p,%p,%p,%p,%d,%d\n",a,&a,p,*p,**p,*p[0]);return 0;}//输出//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]就为数组首元素了。

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

3、二维数组与数组指针

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

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

int main() {int a[10];printf("a:/t%p/n", a);printf("&a:/t%p/n", &a);printf("a+1:/t%p/n", a+1);printf("&a+1:/t%p/n", &a+1);return 0;}//输出://a:0012FF20//&a:0012FF20//a+1:0012FF24/&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

#define TOUCHKEY_BT_SHORT \/*00*/ NO_MSG,\/*01*/ NO_MSG,\/*02*/ NO_MSG,\/*03*/ NO_MSG,\/*04*/ NO_MSG,\/*05*/ NO_MSG,\/*06*/ NO_MSG,\/*07*/ NO_MSG,\/*08*/ NO_MSG,\/*09*/ NO_MSG,#define TOUCHKEY_BT_LONG \/*00*/ NO_MSG,\/*01*/ NO_MSG,\/*02*/ NO_MSG,\/*03*/ NO_MSG,\/*04*/ NO_MSG,\/*05*/ NO_MSG,\/*06*/ NO_MSG,\/*07*/ NO_MSG,\/*08*/ NO_MSG,\/*09*/ NO_MSG,#define TOUCHKEY_BT_HOLD \/*00*/ NO_MSG,\/*01*/ NO_MSG,\/*02*/ NO_MSG,\/*03*/ NO_MSG,\/*04*/ NO_MSG,\/*05*/ NO_MSG,\/*06*/ NO_MSG,\/*07*/ NO_MSG,\/*08*/ NO_MSG,\/*09*/ NO_MSG,#define TOUCHKEY_BT_LONG_UP \/*00*/ NO_MSG,\/*01*/ NO_MSG,\/*02*/ NO_MSG,\/*03*/ NO_MSG,\/*04*/ NO_MSG,\/*05*/ NO_MSG,\/*06*/ NO_MSG,\/*07*/ NO_MSG,\/*08*/ NO_MSG,\/*09*/ NO_MSG,#define KEY_REG_AD_MAX (10)#define KEY_REG_IO_MAX (10)#define KEY_REG_IR_MAX (21)#define KEY_REG_TOUCH_MAX (10)#define KEY_REG_UART_MAX (10)const u16 task_bt_touch_table[4][KEY_REG_TOUCH_MAX] = {/*短按*/ {TOUCHKEY_BT_SHORT},/*长按*/ {TOUCHKEY_BT_LONG},/*连按*/ {TOUCHKEY_BT_HOLD},/*长按抬起*/ {TOUCHKEY_BT_LONG_UP},};typedef struct __KEY_REG {const u16(*_ad)[KEY_REG_AD_MAX];const u16(*_io)[KEY_REG_IO_MAX];const u16(*_ir)[KEY_REG_IR_MAX];const u16(*_touch)[KEY_REG_TOUCH_MAX];const u16(*_uart)[KEY_REG_UART_MAX];} KEY_REG;const KEY_REG task_bt_key = {._ad = task_bt_ad_table,._io = task_bt_io_table,._ir = task_bt_ir_table,._touch = task_bt_touch_table,._uart = task_bt_io_table,//task_bt_touch_table,};typedef struct __TASK_APP {// const char *name;tbool(*skip_check)(void **priv);void *(*init)(void *priv);void (*exit)(void **priv);void (*task)(void *priv);const KEY_REG *key;} TASK_APP;const TASK_APP task_bt_hid_info = {.skip_check = NULL,.init = task_bt_hid_init,.exit = task_bt_exit,.task = task_bt_deal,.key = &task_bt_key,};


总结

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

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