马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
一、size与strlen的区别
二、数组与指针题目剖析
2.0、重要结论
2.1、一维整型数组(sizeof)
2.2、一维字符数组 (常量字符串的strlen)
2.3、一维字符数组 (字符串的sizeof)
2.4、 一维字符数组 (字符串的strlen)
2.5、一维字符数组(指针变量sizeof)
2.6、一维字符数组(指针变量strlen)
2.7、 二维整型数组(sizeof)
2.8、易混淆点
三、数组指针与指针数组
3.1、二者区别
3.2、指针数组(动态开发)
3.3、数组指针(静态二维数组)
3.3、常见误区
一、size与strlen的区别
sizeof(关键字) 1:sizeof是操纵符 2:sizeof盘算操纵数所占内存的⼤⼩,单位是字节 3:不关注内存中存放什么数据 strlen(函数) 1:strlen是库函数,使⽤必要包含头⽂<string.h> 2:srtlen是求字符串⻓度的,统计的是 \0 之前字符的个数 3:关注内存中是否有 \0 ,如果没有 \0 ,就会连续往后找,可能会越界 二、数组与指针题目剖析
2.0、重要结论
- sizeof(数组名) :这里的数组名指的是整个数组
- &数组名 :这里的数组名指的是整个数组,取出的是地址
- 反之代表的都是首元素的地址(X64->8 X86->4)
2.1、一维整型数组(sizeof)
- int main()
- {
- int a[] = { 1,2,3,4 };
- printf("%zd\n", sizeof(a)); //16,表示取出整个数组的大小
- printf("%zd\n", sizeof(a + 0)); //8,表示首元素的地址大小
- printf("%zd\n", sizeof(*a)); //4,表示首元素的值的sizeof
- printf("%zd\n", sizeof(a + 1)); //8,表示第二个元素的地址大小
- printf("%zd\n", sizeof(a[1])); //4,表示第二个元素的值的sizeof
- printf("%zd\n", sizeof(&a)); //8,表示的是整个数组名的地址大小
- printf("%zd\n", sizeof(*&a)); //16,*&抵消,即sizeof(a),表示取出整个数组的大小
- printf("%zd\n", sizeof(&a + 1));//8,表示跳过整个数组之后的那个地址的大小
- printf("%zd\n", sizeof(&a[0])); //8,表示首元素的地址大小
- printf("%zd\n", sizeof(&a[0] + 1));//8,表示第二个元素的地址大小
- return 0;
- }
复制代码 对于每一个盘算的表明都在对应的注释。
打印效果:
2.2、一维字符数组 (常量字符串的strlen)
- int main()
- {
- //strlen参数是char*,从当前位置开始找'\0'
- char arr[] = { 'a','b','c','d','e','f' }; //常量字符串,无'\0'
- //printf("%zd\n", strlen(arr)); //error,从首元素出向后找'\0',无'\0'
- //printf("%zd\n", strlen(arr + 0)); //error,从首元素出向后找'\0',无'\0'
- //printf("%zd\n", strlen(*arr)); //非法访问,表示解引用出首元素,即ASCII为97,0x00000061处,构成非法访问
- //printf("%zd\n", strlen(arr[1])); //非法访问,表示从第二个元素开始向后找,即ASCII为98,0x00000062处,构成非法访问
- //printf("%zd\n", strlen(&arr));//error,表示从整个数组的起始地址向后找'\0'
- //printf("%zd\n", strlen(&arr + 1)); //error,表示从整个数组末尾的下一个位置向后找'\0'
- //printf("%zd\n", strlen(&arr[0] + 1));//error,表示从数组首元素地址向后找'\0'
- return 0;
- }
复制代码 对于每一个盘算的表明都在对应的注释。
2.3、一维字符数组 (字符串的sizeof)
- int main()
- {
- char arr[] = "abcdef";
- printf("%zd\n", sizeof(arr)); //7,表示计算整个数组的大小
- printf("%zd\n", sizeof(arr + 0));//8 ,表示计算首元素地址的大小
- printf("%zd\n", sizeof(*arr)); //1,表示计算'a'的大小
- printf("%zd\n", sizeof(arr[1]));//1,表示计算'b'的大小
- printf("%zd\n", sizeof(&arr)); //8,表示计算整个数组的地址大小
- printf("%zd\n", sizeof(&arr + 1));//8,表示计算整个数组的下一个位置地址的大小
- printf("%zd\n", sizeof(&arr[0] + 1));//8,表示计算第二个元素地址的大小
- return 0;
- }
复制代码 对于每一个盘算的表明都在对应的注释。
打印效果:
2.4、 一维字符数组 (字符串的strlen)
- int main()
- {
- char arr[] = "abcdef";
- printf("%zd\n", strlen(arr)); //6,表示计算整个数组的长度
- printf("%zd\n", strlen(arr + 0));//6 ,表示计算数组从首元素地址开始的长度
- //printf("%zd\n", strlen(*arr)); //非法访问,表示解引用出首元素,即ASCII为97,0x00000061处,构成非法访问
- //printf("%zd\n", strlen(arr[1])); //非法访问,表示从第二个元素开始向后找,即ASCII为98,0x00000062处,构成非法访问
- printf("%zd\n", strlen(&arr)); //6,表示计算数组从整个数组的地址开始的长度
- //printf("%zd\n", strlen(&arr + 1)); //error,表示计算从整个数组下一个位置开始的长度
- printf("%zd\n", strlen(&arr[0] + 1));//5,表示计算数组从第二个元素地址开始的长度
- }
复制代码 对于每一个盘算的表明都在对应的注释。
打印效果:
2.5、一维字符数组(指针变量sizeof)
- int main()
- {
- char* p = "abcdef"; //p是指针变量,指向第一个元素的地址
- printf("%zd\n", sizeof(p)); //8,表示计算指针变量所指向'a'地址的大小
- printf("%zd\n", sizeof(p + 1)); //8,表示计算指针变量所指向'b'地址的大小
- printf("%zd\n", sizeof(*p)); //1,表示计算指针变量所指向内容'a'(char)的大小
- printf("%zd\n", sizeof(p[0])); //1,表示计算指针变量所指向内容'a'(char)的大小
- printf("%zd\n", sizeof(&p)); //8,表示计算指向p指针的指针变量的大小(二级指针)
- printf("%zd\n", sizeof(&p + 1)); //8,表示计算指向p指针下一个位置的指针变量的大小(二级指针)
- printf("%zd\n", sizeof(&p[0] + 1));//8,表示计算指针变量所指向'b'地址的大小
- return 0;
- }
复制代码 对于每一个盘算的表明都在对应的注释。
打印效果:
2.6、一维字符数组(指针变量strlen)
- int main()
- {
- char* p = "abcdef";
- printf("%zd\n", strlen(p)); //6,表示计算数组从'a'开始的长度
- printf("%zd\n", strlen(p + 1));//5 ,表示计算数组从'b'开始的长度
- //printf("%zd\n", strlen(*p)); //非法访问,表示解引用出首元素'a',即ASCII为97,0x00000061处,构成非法访问
- //printf("%zd\n", strlen(p[0])); //非法访问,表示解取出首元素'a',即ASCII为97,0x00000061处,构成非法访问
- //printf("%zd\n", strlen(&p)); //error,表示计算二级指针的长度
- //printf("%zd\n", strlen(&p + 1)); //error,表示计算二级指针下一个位置的长度
- printf("%zd\n", strlen(&p[0] + 1));//5,表示计算数组从'b'开始的长度
- return 0;
- }
复制代码 对于每一个盘算的表明都在对应的注释。
打印效果:
2.7、 二维整型数组(sizeof)
- int main()
- {
- //sizeof(数组名) 这里的数组名指的是整个数组
- //&数组名 这里的数组名指的是整个数组,取出的是地址
- //其它情况均为数组首元素的地址
- int a[3][4] = { 0 };
- printf("%zd\n", sizeof(a)); //48,计算的是整个数组的大小
- printf("%zd\n", sizeof(a[0][0]));//4,计算的是整个数组的第一个元素(int)的大小
- printf("%zd\n", sizeof(a[0])); //16,a[0]也是数组名(首行),计算的是整个第一行的大小
- printf("%zd\n", sizeof(a[0] + 1)); //8,这里a[0]并没有单独放在sizeof里面,代表第一行的第一个元素的地址,再+1,即&a[0][1]
- printf("%zd\n", sizeof(*(a[0] + 1))); //4,*&a[0][1],即计算a[0][1](int)的大小
- printf("%zd\n", sizeof(a + 1)); //8,这里a并没有单独放在sizeof里面,代表第一行的地址,再+1,即&a[1]
- printf("%zd\n", sizeof(*(a + 1))); //16,*&a[1],即计算a[1](int[4])的大小
- printf("%zd\n", sizeof(&a[0] + 1)); //8,&a[0]即取出第一行的地址,再+1,计算第二行的地址,&a[1]
- printf("%zd\n", sizeof(*(&a[0] + 1))); //16,*&a[1],即计算a[1](int[4])的大小
- printf("%zd\n", sizeof(*a)); //16,这里的a并没有单独放在sizeof内,a为&a[0],*a为a[0],计算整个a[0]的大小
- printf("%zd\n", sizeof(a[3]));//16,这里的a[3],即等价于a[0],a[1],a[2],并不造成越界的问题。计算的是类型int[4]
- return 0;
- }
复制代码 对于每一个盘算的表明都在对应的注释。
打印效果:
2.8、易混淆点
- a[][] int(单个元素)
- a[0] int[4](第一行,4个int的数组)
- a[0] → int* (在表达式中退化为指针)
- a int[3][4](整个二维数组)
- a → int(*)[4](在表达式中退化为指向行的指针)
- int* arr[]
- int (*arr)[]
复制代码 举个例子:
- 对于二维数组a[][]中的a[],他的数据类型是int[4],但汇编时间会退化成int*,也就是我们常明白的行指针,但本质上的类型并不是指针,绝不能当做指针数组来明白。
- 而sizeof本质上盘算的是数据的类型,也并不会因为越界访问而报错。
- 对于a[][]中而言,他的数据类型是int[3][4],但汇编时间会退化成int(*)[4],也就是我们常明白的数组指针,绝不能当做二级指针来明白。
三、数组指针与指针数组
3.1、二者区别
3.2、指针数组(动态开发)
- int *ptr_arr[3]; // 3 个 int* 组成的数组
- for (int i = 0; i < 3; i++) {
- ptr_arr[i] = malloc(4 * sizeof(int)); // 每行 4 个 int
- }
- ptr_arr[1][2] = 10; // 访问第 2 行的第 3 个元素
复制代码 3.3、数组指针(静态二维数组)
- int a[3][4] = {0};
- int (*arr_ptr)[4] = a; // 指向 a[0](第一行)
- arr_ptr[1][2] = 20; // 访问 a[1][2]
复制代码 3.3、常见误区
❌ int **p 和 int (*p)[4] 不是一回事!
- int **p 适用于 指针数组(动态分配)。
- int (*p)[4] 适用于 静态二维数组。
❌ int *p[4] 和 int (*p)[4] 完全差别!
- int *p[4] 是 指针数组(4 个 int*)。
- int (*p)[4] 是 数组指针(指向 int[4])。
|