sizeof(数组名) —— 数组名表示整个数组
&数组名 —— 数组名表示整个数组,取出是整个数组的地址
除此之外,所有的数组名都是数组首元素地址
int a[] = { 1,2,3,4 };
//16
//sizeof(a),计算整个数组占内存空间大小,此时a表示整个数组
printf("%d\n", sizeof(a));
//4/8,当a参与运算,此时不再是表示整个数组,而是表示数组首元素地址
printf("%d\n", sizeof(a + 0));
//4,a参与运算,计算的是数组第一个元素的大小
printf("%d\n", sizeof(*a));
//4/8,计算数组第二个元素的地址 所占空间大小
printf("%d\n", sizeof(a + 1));
//4,计算数组第二个元素大小
printf("%d\n", sizeof(a[1]));
//4/8,取出整个数组的地址,整型地址占内存4/8字节。
printf("%d\n", sizeof(&a));
//16,*和&可以相互抵消,仅仅计算数组a的所占空间大小
printf("%d\n", sizeof(*&a));
//4/8,跳过整个数组,整型地址占32位机器内存4字节
printf("%d\n", sizeof(&a + 1));
//4/8,取数组第一个元素的地址,地址占4/8字节
printf("%d\n", sizeof(&a[0]));
//4/8,取第一个元素地址,后移一位是第二个元素地址,地址占4/8字节
printf("%d\n", sizeof(&a[0] + 1));
char arr[] = { 'a','b','c','d','e','f' };
//6.计算整个数组占空间大小
printf("%d\n", sizeof(arr));
//4/8,参与运算,数组首元素地址
printf("%d\n", sizeof(arr + 0));
//1,数组首元素地址解引用,计算数组首元素占空间大小
printf("%d\n", sizeof(*arr));
//1,计算数组第二个元素占空间大小
printf("%d\n", sizeof(arr[1]));
//4/8,计算整个数组的地址大小
printf("%d\n", sizeof(&arr));
//4/8,跳过整个数组长度后,计算空间大小
printf("%d\n", sizeof(&arr + 1));
//4/8,计算第二位元素所占空间大小
printf("%d\n", sizeof(&arr[0] + 1));
//随机值,从数组首元素开始向后计算长度,没找到\0,结果随机值
printf("%d\n", strlen(arr));
//随机值,同上,没找到结束标志\0,结果随机值
printf("%d\n", strlen(arr + 0));
//err,计算数组首元素长度,相当于strlen('a'),没有这个功能,报错
printf("%d\n", strlen(*arr));
//err,相当于计算'b'长度,没有这个功能,报错
printf("%d\n", strlen(arr[1]));
//随机值,从首元素地址开始向后计算长度,没有明确\0,结果随机值
printf("%d\n", strlen(&arr));
//随机值-6,跳过整个数组(数组占内存6字节)后计算长度,比上一句代码少6位数据,结果还是随机值
printf("%d\n", strlen(&arr + 1));
//随机值-1,从数组第二位元素开始计算长度,比从开头计算少一。
printf("%d\n", strlen(&arr[0] + 1));
char arr[] = "abcdef";
//a b c d e f \0
//7,有隐藏的\0结束标志,所以占用空间7位
printf("%d\n", sizeof(arr));
//4/8,arr参与运算表示首元素地址,地址占空间4/8位字节
printf("%d\n", sizeof(arr + 0));
//1,首元素地址解引用,得到数组首元素,char类型占用1字节
printf("%d\n", sizeof(*arr));
//1,数组第二位元素占用1字节
printf("%d\n", sizeof(arr[1]));
//4/8,整个数组的地址,只要是地址就占用4/8
printf("%d\n", sizeof(&arr));
//4/8,跳过整个数组长度后,计算地址
printf("%d\n", sizeof(&arr + 1));
//4/8,先指向数组首元素,再后移指向数组第二位元素,最后计算地址
printf("%d\n", sizeof(&arr[0] + 1));
//6,有结束标志\0,可以正常计算数组长度
printf("%d\n", strlen(arr));
//6,从首元素开始计算长度,遇到\0结束
printf("%d\n", strlen(arr + 0));
//err,还是把字符'a'传递进去计算,报错
printf("%d\n", strlen(*arr));
//err,把字符'b'传递进去计算,报错
printf("%d\n", strlen(arr[1]));
//6,计算整个数组长度
printf("%d\n", strlen(&arr));
//随机值,跳过整个数组,不知道结束标志\0位置,所以随机值
printf("%d\n", strlen(&arr + 1));
//5,从数组第二位元素开始计算,结果5
printf("%d\n", strlen(&arr[0] + 1));
char* p = "abcdef";
//p -> [a,b,c,d,e,f,\0]
//4/8,p是个地址,指向'a'
printf("%d\n", sizeof(p));
//4/8,指针后移一位,还是地址
printf("%d\n", sizeof(p + 1));
//1,地址指向'a',解引用就是计算'a'的长度
printf("%d\n", sizeof(*p));
//1,计算'a'的长度
printf("%d\n", sizeof(p[0]));
//4/8,取p的地址计算,是地址就是4/8
printf("%d\n", sizeof(&p));
//4/8,跳过整个p,还是地址
printf("%d\n", sizeof(&p + 1));
//4/8,计算'b'的地址
printf("%d\n", sizeof(&p[0] + 1));
//6,p指针指向a,从a开始计算长度,遇到\0结束
printf("%d\n", strlen(p));
//5,指针后移一位,从b开始计算长度
printf("%d\n", strlen(p + 1));
//err,p指针指向a,解引用得到a,函数无法计算字符a长度
printf("%d\n", strlen(*p));
//err,函数无法计算字符a长度
printf("%d\n", strlen(p[0]));
//随机值,取p指针的地址,计算长度,无法知道\0位置,随机值
printf("%d\n", strlen(&p));
//随机值,跳过一个p指针的地址,还是无法知道\0位置,随机值
printf("%d\n", strlen(&p + 1));
//5,取到a的地址,后移一位得到b,也就是从b开始计算长度。
printf("%d\n", strlen(&p[0] + 1));
//二维数组
int a[3][4] = { 0 };
/*
0 0 0 0
0 0 0 0
0 0 0 0
*/
//48,计算整个数组大小
printf("%d\n", sizeof(a));
//4,计算二维数组第一行第一个元素大小
printf("%d\n", sizeof(a[0][0]));
//16,计算二维数组第一行大小
printf("%d\n", sizeof(a[0]));
//4,计算数组第一行第二个元素的地址大小
printf("%d\n", sizeof(a[0] + 1));
//4,数组第一行第二个元素大小
printf("%d\n", sizeof(*(a[0] + 1)));
//4,数组首元素地址后移一位,再计算大小
printf("%d\n", sizeof(a + 1));
//16,数组首元素后移一位,再解引用得到第二行元素,最后再计算第二行元素大小
printf("%d\n", sizeof(*(a + 1)));
//4,数组首元素地址后移一位,再计算大小
printf("%d\n", sizeof(&a[0] + 1));
//16,数组首元素后移一位,再解引用得到第二行元素,最后再计算第二行元素大小
printf("%d\n", sizeof(*(&a[0] + 1)));
//16,数组首元素解引用,得到第一行元素,最后计算第一行元素大小
printf("%d\n", sizeof(*a));
//16,计算数组第四行元素大小,
//因为sizeof只表面计算表达式结果,不会真正的访问这块空间,所以不在乎这块空间是否存在
printf("%d\n", sizeof(a[3]));
sizeof ( ),并不会把表达式的数据结果保存下来,也不会去真正访问内存区域。
short s = 5;
int a = 4;
printf("%d\n", sizeof(s = a + 5));
printf("%d\n", s);
int arr[3] = { 0 };
printf("%d\n", sizeof(arr[4]));
数组名的意义:
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
解析:
//2, 5
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
//&a取出整个数组地址,+1跳过整个数组
int* ptr = (int*)(&a + 1);
//*(a+1),首元素地址后移一位,得到2
//*(ptr - 1),ptr原本指向数组后面空间,-1就前移一位,指向数据5
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1);
int* ptr2 = (int*)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
}
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
文字+图解:
仔细看,二维数组初始化内容是逗号表达式,逗号表达式末尾元素才是二维数组中的数据。
p = a[0],相当于让指针 p 指向二维数组中的第一行数据
p[0],相当于 p+0,指针 p 没有发生改变。按照 %d 形式打印,结果为 1。
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
文字+图解:
前三行代码执行后,内存情况:
&p[4][2] - &a[4][2]
指向如图绿色方块。以%d形式打印,将输出彼此相差的 -4。int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
文字+图解:
执行完前三段代码,内存情况如图:
创建二维数组。&aa+1,取二维数组的地址,+1跳过整个二维数组,最后赋值给整型指针 ptr1。
*(ptr1 - 1)
,ptr1指针向前移动一位,指向10,解引用得到数据10.
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
文字+图解:
执行前两段代码,内存情况如图:
pa++,指针下移一位,最后解引用输出结果 at。
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *-- * ++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return 0;
}
文字+图解:
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
前三段代码执行后内存情况:
printf("%s\n", **++cpp);
cpp指针向下移动一位,经过两次解引用得到 POINT。
printf("%s\n", *-- * ++cpp + 3);
这段代码复杂点
++cpp 指针继续下移一位,解引用得到 c+1.
*(--(c+1)),会把 c+1 变成 c,解引用得到 *c 第一个元素 "ENTER"
最后面的 +3,因为 *c 是 "ENTER" 的首元素地址,向后推移三位再输出,结果为:ER
printf("%s\n", *cpp[-2] + 3);
如果不好理解 *cpp[-2] + 3,可以转换成 **(cpp-2)+3
cpp-2,指针向上移动两位到 c+3,
两次解引用,得到 *c 指向的元素 "FIRST",
因为 *c 是指向 "FIRST"的首元素,+3向后数三位,然后才计算输出结果:ST
printf("%s\n", cpp[-1][-1] + 1);
可以把 cpp[-1][-1] + 1 转换成 *(*(cpp-1)-1)+1,
cpp-1,指针指向 *cp 数组的第二位 c+2,
解引用得到 c+2,然后 c+2-1 得到 c+1,导致修改了 *cp 第二位元素指向 *c 第二位地址,
再次解引用,得到 "NEW",最后一个+1,让 *c 指针向后移动一位,才开始计算结果:EW。
关于c语言指针这几篇文章,搞了半个星期,终于结束了~