指针和数组解析
数组名通常指的是首元素的地址,但有两个例外:
1.sizeof(数组名),sizeof里面单独存放数组名,这里的数组名代表整个数组。
2.&数组名,&后面单独接数组名,这里的数组名代表整个数组。
任意表达式都有两个属性,值属性和类型属性,sizeof只会计算表达式的类型属性,并不会对表达式的值属性进行修改。
1.sizeof和整型数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//数组名单独放在sizeof内部,代表整个数组,类型是int [4],大小16个字节
printf("%d\n", sizeof(a + 0));//这里的数组名并不是单独放在sizeof内部,代表首元素的地址,首元素的地址加0依旧是首元素的地址,是地址也就是指针大小就是4/8个字节
printf("%d\n", sizeof(*a));//数组名不单独放在sizeof内部,代表首元素的地址,解引用得到第一个元素,类型是int,大小是4个字节
printf("%d\n", sizeof(a + 1));//这里的数组名代表首元素的地址,加1代表第二个元素的地址,大小是4/8个字节
printf("%d\n", sizeof(a[1]));//a[1]是第二个元素,类型是int,大小4个字节
printf("%d\n", sizeof(&a));//数组名单独放在&后面代表整个数组,&a的类型是int(*)[4],是指针,大小是4/8个字节
printf("%d\n", sizeof(*&a));//数组名单独放在&后面,代表整个数组,*&a的类型是*(int(*)[4])==int [4],大小是16个字节
printf("%d\n", sizeof(&a + 1));//&a+1跳过了整个数组,类型是int(*)[4],大小是4/8个字节
printf("%d\n", sizeof(&a[0]));//&a[0]是首元素的地址,大小是4/8个字节
printf("%d\n", sizeof(&a[0] + 1));//&a[0]+1是第二个元素的地址,大小是4/8个字节
2.sizeof和字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//arr单独放在sizeof内部,代表整个数组,类型是char [6],大小是6个字节
printf("%d\n", sizeof(arr + 0));//这里的arr代表首元素的地址,加0依旧是首元素的地址,大小是4/8个字节
printf("%d\n", sizeof(*arr));//*arr代表首元素,类型是char,大小是1个字节
printf("%d\n", sizeof(arr[1]));//arr[1]代表第二个元素,类型是char,大小是1个字节
printf("%d\n", sizeof(&arr));//&arr取出的是整个数组的地址,类型是char(*)[6],大小是4/8个字节
printf("%d\n", sizeof(&arr + 1));//&arr+1是取出整个数组的地址后跳过整个数组,类型依旧是char(*)[6],大小是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是首元素的地址,加1是第二个元素的地址,类型是char*,大小是4/8个字节
3.字符数组和strlen
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//strlen必须找到'\0'才停止,这里的arr是首元素的地址,但数组内没有存放'\0',结果是随机值
printf("%d\n", strlen(arr + 0));//这里的arr+0依旧是首元素地址,结果是随机值
printf("%d\n", strlen(*arr));//err
//*arr是首元素'a',ASCII码值为97
//strlen的参数部分需要传入一个地址,当我们传递的是'a'时,就是将97作为地址传递给strlen
//那么strlen就会从97这个地址开始统计字符串长度,这就非法访问了
printf("%d\n", strlen(arr[1]));//err
//arr[1]是第二个元素'b',ASCII码值是98,同样也造成了非法访问
printf("%d\n", strlen(&arr));//&arr取出的是整个数组的地址,但值是和数组首元素地址是一样的,所以strlen依旧是从数组的第一个元素开始查找,结果是随机值
printf("%d\n", strlen(&arr + 1));//&arr+1是取出整个数组的地址后加整个数组的大小,strlen将从数组的最后一个元素的下一个位置开始查找,结果依旧是随机值
printf("%d\n", strlen(&arr[0] + 1));//&arr[0]+1是第二个元素的地址,结果是随机值
4.字符串数组和sizeof
char arr[] = "abcdef";
//arr里面存放的是{'a','b','c','d','e','f','\0'},有7个元素
printf("%d\n", sizeof(arr));//arr单独放在sizeof内部,代表整个数组,类型是char [7],大小是7个字节
printf("%d\n", sizeof(arr + 0));//arr+0代表首元素的地址,类型是char*,大小是4/8个字节
printf("%d\n", sizeof(*arr));//*arr是首元素'a',类型是char,大小是1个字节
printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素'b',类型是char,大小是1个字节
printf("%d\n", sizeof(&arr));//&arr取出是是整个数组的地址,类型是char(*)[7],大小是4/8个字节
printf("%d\n", sizeof(&arr + 1));//&arr+1指向数组最后一个元素后面的地址,类型是char(*)[7],大小是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,类型是char*,大小是4/8个字节
5.字符串数组和strlen
char arr[] = "abcdef";
//arr里面存放的是{'a','b','c','d','e','f','\0'},有7个元素
printf("%d\n", strlen(arr));//arr在strlen内部代表首元素的地址,strlen能找到'\0',结果是6
printf("%d\n", strlen(arr + 0));//arr+0依旧是首元素的地址,结果是6
//printf("%d\n", strlen(*arr));//err
//*arr是'a',传入strlen会导致非法访问
//printf("%d\n", strlen(arr[1]));//err
//arr[1]是'b',传入strlen依旧会导致非法访问
printf("%d\n", strlen(&arr));//&arr的值和首元素地址的值相同,传入strlen就是strlen从首元素开始找,结果是6
printf("%d\n", strlen(&arr + 1));//&arr+1指向的位置已经跳到'\0'的后面一位,结果是随机值
printf("%d\n", strlen(&arr[0] + 1));//&arr[0]+1是第二个元素的地址,结果是5
6.常量字符串和sizeof
char* p = "abcdef";
printf("%d\n", sizeof(p));//p是一个指针变量,大小是4/8个字节
printf("%d\n", sizeof(p + 1));//p+1是一个指向'b'位置的指针变量,大小是4/8个字节
printf("%d\n", sizeof(*p));//*p就是'a',类型是char,大小是1个字节
printf("%d\n", sizeof(p[0]));//p[0]也是'a',类型char,大小是1个字节
printf("%d\n", sizeof(&p));//&p是p的地址,类型是char**,大小是4/8个字节
printf("%d\n", sizeof(&p + 1));//&p+1依旧是地址,大小是4/8个字节
printf("%d\n", sizeof(&p[0] + 1));//&p[0]+1是'b'的地址,大小是4/8个字节
7.常量字符串和strlen
char* p = "abcdef";
printf("%d\n", strlen(p));//strlen从字符串首元素地址开始找,结果是6
printf("%d\n", strlen(p + 1));//从第二个元素的地址开始找,结果是5
//printf("%d\n", strlen(*p));//*p依旧是'a',会非法访问,err
//printf("%d\n", strlen(p[0]));//p[0]是'a',传入strlen会非法访问,err
printf("%d\n", strlen(&p));//从&p的位置开始找'\0',结果是随机值
printf("%d\n", strlen(&p + 1));//从&p+1的位置开始找'\0',结果是随机值
printf("%d\n", strlen(&p[0] + 1));//从第二个元素的地址开始找'\0',结果是5
8.二维数组和sizeof
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//a代表整个数组,类型是int [3][4],大小是3*4*4=48个字节
printf("%d\n", sizeof(a[0][0]));//第一行第一个元素,类型是int,大小是4个字节
printf("%d\n", sizeof(a[0]));//a[0]是第一行这个一维数组的数组名,单独放在sizeof内部,计算的是第一行整个一维数组的大小,类型是int [4],大小是16个字节
printf("%d\n", sizeof(a[0] + 1));//a[0]是第一行数组的数组名,没有单独放在sizeof内部,代表的也就是第一行首元素a[0][0]的地址,加1就是第一行第二个元素的地址,类型是int*,大小是4/8个字节
printf("%d\n", sizeof(*(a[0] + 1)));//第二行的首个元素,类型是int,大小是4个字节
printf("%d\n", sizeof(a + 1));//a是整个二维数组首元素的地址,类型是int(*)[4],加1是第二行的地址,类型依旧是int(*)[4],大小是4/8个字节
printf("%d\n", sizeof(*(a + 1)));//a+1的类型是int(*)[4],解引用后类型就成了int [4],大小是16个字节
printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,类型是int(*)[4],大小是4/8个字节
printf("%d\n", sizeof(*(&a[0] + 1)));//对第二行的地址进行解引用,类型是int [4],大小是16个字节
printf("%d\n", sizeof(*a));//a是首元素的地址,也就是第一行的地址,类型是int(*)[4],解引用后的类型就是int [4],大小是16个字节
printf("%d\n", sizeof(a[3]));//a[3]的类型和a[0]的类型相同,是int [4],大小是16个字节