#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//随机数
printf("%d\n", strlen(arr + 0));//随机数
//printf("%d\n", strlen(*arr));//错误
//printf("%d\n", strlen(arr[1]));//错误
printf("%d\n", strlen(&arr));//随机数a
printf("%d\n", strlen(&arr + 1));//随机数a-6
printf("%d\n", strlen(&arr[0] + 1));//随机数a-1
return 0;
}
问:C语言中,strlen()必须接收一个地址才行吗?
ChatIA答:
是的,strlen() 函数需要接收一个字符数组的地址,也就是一个指向字符数组首个元素的指针。这是因为 strlen() 函数的作用是计算字符串的长度,而字符串是以 null 字符(‘\0’)结尾的字符数组。因此只有通过传递指向字符数组首个元素的指针,才能让 strlen() 函数在字符数组中扫描查找 null 字符并计算字符串的长度。
如果你传递的不是字符数组的首个元素的指针,那么 strlen() 函数无法确定字符数组的起始位置,而且可能还会读取无效内存,导致程序出现错误。因此强烈建议在调用 strlen() 函数时传递字符数组的地址。
问:上述代码中,当strlen(&arr)时,VS2015环境下报错“const char ”与“char ()[6]”的间接级别不同。
ChatAI答:
是的,“const char*” 和 “char (*)[6]” 的间接级别是不同的。
对于前者,它是一个指向字符的常量指针(或者说是指向字符串的指针),并且是单个字符的指针。指针加1时,指向的是下一个字符,因此它是一个指向内存中某个连续字符单元的指针。
对于后者,它是一个指向字符数组的指针,该字符数组有6个元素。指针加1时,指向的是下一个数组,因此它是一个指向一个连续数组块的指针。
这种类型之间的区别也可以通过下面的代码来说明:
const char *str1 = "hello";
char str2[6] = "world";
char (*p)[6] = &str2;
/* 指针 str1 加1,指向下一个字符 */
printf("%c\n", *(str1+1)); // e
/* 指针 p 加1,指向下一个数组 */
printf("%c\n", *(*p+1)); // o
从输出结果来看,可以看到这两种类型的指针使用方式是不同的。
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7 sizeof计算的是数组大小,7*1=6个字节
printf("%d\n", sizeof(arr + 0));//4/8 arr是首元素的地址,arr+0还是首元素的地址,地址大小是4/8字节
printf("%d\n", sizeof(*arr));//1 arr是首元素地址,*arr就是首元素,首元素是字符大小是一个字节
printf("%d\n", sizeof(arr[1]));//1 arr是第二个元素
printf("%d\n", sizeof(&arr));//4/8 &arr虽然是数组的地址,但还是地址,地址的大小是4/8个字节
printf("%d\n", sizeof(&arr + 1));//4/8 &arr+1是跳过整个数组后的地址,地址大小是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//4/8 第二个元素的地址
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr + 0));//6
//printf("%d\n", strlen(*arr));//错误
//printf("%d\n", strlen(arr[1]));//错误
printf("%d\n", strlen(&arr));//6 &arr-数组的地址-数组指针char(*p)[7]=&arr;
printf("%d\n", strlen(&arr + 1));//随机数
printf("%d\n", strlen(&arr[0] + 1));//5
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char *p = "abcdef";
printf("%d\n", sizeof(p));//4/8 计算指针变率p的大小
printf("%d\n", sizeof(p+1));//4/8 p+1得到的是字符b的地址
printf("%d\n", sizeof(*p));//1 *p就是字符串的第一个字符'a'
printf("%d\n", sizeof(p[0]));//1 int arr[10]; arr[0]==*(arr+0) p[0]==*(p+0)=='a'
printf("%d\n", sizeof(&p));//4/8 地址
printf("%d\n", sizeof(&p + 1));//4/8 地址
printf("%d\n", sizeof(&p[0] + 1));//4/8 地址
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char *p = "abcdef";
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p+1));//5
//printf("%d\n", strlen(*p));//报错
//printf("%d\n", strlen(p[0]));//报错
printf("%d\n", strlen(&p));//随机值
printf("%d\n", strlen(&p + 1));//随机值
printf("%d\n", strlen(&p[0] + 1));//5
return 0;
}
问:指针与数组的转换
ChatAI答:
指针与数组在 C 语言中是密不可分的概念,在很多情况下可以互相转换。
数组可以看做是一个连续的内存空间,在编译时就已经确定了其大小,而指针可以指向这个内存空间的起始地址。
数组名转换为指针
在 C 语言中,数组名代表数组第一个元素的地址,它可以通过自动转换成为同类型指针。所以,在大多数情况下,数组名可以被当作指针来使用。例如:
int a[10];
int *p = a;
上面的代码中,a 是一个数组名,它被自动转换成了 int* 类型的指针,指向 a 数组的首元素,p 指针指向 a 数组的第一个元素。
指针转换为数组名
指针也可以转换为数组名。如果一个指针指向了一个数组的首元素,那么这个指针也可以被当作数组名来使用。例如:
int a[10];
int *p = a;
int (*q)[10] = (int (*)[10])p;
上面的代码中,p 指针指向 a 数组的首元素,再将 p 指针转换为 (int (*)[10]) 类型的指针,可以得到一个指向整个 a 数组的指针。这个指针可以当作数组名使用,例如:
(*q)[0] = 1; // 修改数组第一个元素的值
printf("%d", a[0]); // 输出结果为 1
总之,指针与数组之间的转换,可以使得我们在编写代码时具有更大的灵活性。但是,在使用过程中要格外注意指针与数组的类型,防止类型不匹配导致的错误。
自行记忆:星就相当于是[],而&则是可以和星和[]相抵消。(仅限于记忆,三者关系不能完全等价)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//48
printf("%d\n", sizeof(a[0][0]));//4
printf("%d\n", sizeof(a[0]));//16 a[0]相当于第一行作为一维数组的数组名,
//sizeof(arr[0])把数组名单独放在sizeof()内,计算的是第一行的大小
printf("%d\n", sizeof(a[0] + 1));//4/8 a[0]是第一行的数组名,数组名此时是首元素地址,其实就是第一行第一个元素的地址,
//所以a[0]+1就是第一行第二个元素的地址,地址大小是4/8个字节
printf("%d\n", sizeof(*(a[0] + 1)));//4 *(a[0] + 1)是第一行第二个元素,大小是4个字节
printf("%d\n", sizeof(a+1));//4/8 a是二维数组的数组名,没有sizeof(数组名),也没有&(数组名),所以a是首元素地址,
//而把二维数组看成一维数组时,二维数组的首元素是他的第一行,a就是第一行(首元素)的地址,a+1就是第二行的地址。
printf("%d\n", sizeof(*(a+1)));//16 sizeof(a[1])计算第二行的大小,单位是16字节
printf("%d\n", sizeof(&a[0]+1));//4/8 第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1)));//16 计算第二行的大小,单位是字节
printf("%d\n", sizeof(*a));//16 a是首元素地址-第一行的地址,*a就是第一行,sizeof(*a)就是计算第一行的大小
printf("%d\n", sizeof(a[3]));//16
return 0;
}