#define _CRT_SECURE_NO_WARNINGS #includeint main() { char a[] = { 'a','b','c','d','e','f' }; //观察这个字符数组,可知它是6个元素 //所以根据char类型,可知这个数组的大小是6 printf("%d", sizeof(a)); //数组名在大多数情况下都是首元素地址,唯有两种情况不是 //1.sizeof括号里只有单独的的数组名,其他什么都没有,这种表示的是整个数组的大小 //2.&a,以这种形式出现的数组名也表示整个数组的地址 //所以这里的结果是6 printf("%d", sizeof(a+0)); //这里的a表示的是数组首元素地址+0,跳过0个字节的大小,所以结果是4 printf("%d", sizeof(*a)); //这里的a表示的是数组首元素地址,对a进行解引用,所以这里表示的‘a’,所以结果是1 printf("%d", sizeof(a[1])); //这里直接表示的就是数组的a[1]元素,所以结果是1 printf("%d", sizeof(&a)); //这里的&a表示的整个数组的地址,但是要知道地址的大小只有4或者8个,这里使用的x86平台,所以结果是4 printf("%d", sizeof(&a+1)); //这里表示的是数组地址跳过一个6个字符的数组,最终指向一个地址,所以结果是4 printf("%d", sizeof(&a[0]+1)); //这里表示的数组的元素的地址,所以结果是4; //谨记!指针的大小是4/8,根据平台的不同而决定他的大小 return 0; }
上面的代码分别讲述了指针的大小问题,以及数组名在不同情况下所代表的的不同意义
#define _CRT_SECURE_NO_WARNINGS #includeint main() { char a[] = { 'a','b','c','d','e','f' }; printf("%d", strlen(a)); //strlen这个函数计算的是字符数组的大小,遇到‘ ’才会停下计数,所以这里的结果是随机值 printf("%d", strlen(a+0)); //同上面一样的道理,所以结果是随机值 printf("%d", strlen(*a)); //根据CPLUSPLUS上面对strlen函数的规定,里面放的指针类型,而这里的*a代表的是数组的首元素,不符合规定,程序会报错 printf("%d", strlen(a[1])); //同上面一样的道理,所以这里也会报错 printf("%d", strlen(&a)); //这里&a代表的是取整个数组的地址,但也是从首元素的地址开始,所以跟上面的第一个的结果一样,是随机值 printf("%d", strlen(&a+1)); //这里的&a代表的也是取整个数组的地址,+1代表跳过整个数组大小的地址,所以结果是上面的结果-6,也就是随机值-6 printf("%d", strlen(&a[0]+1)); //这里代表的是数组首元素的地址,+1代表的跳过一个元素大小的地址,所以结果是随机值-1 return 0; }
这里讲解了strlen函数的用法,以及数组名所代表的的意义,以及一些指针运算的问题
#define _CRT_SECURE_NO_WARNINGS #includeint main() { char a[] = "abcdef"; printf("%d", sizeof(a));//4 //这里的数组a存放的方式会在后面默认带有‘ ’,所以数组的大小是7,sizeof后面出现的a代表的是整个数组的大小 printf("%d", sizeof(a+0));//4 //这里sizeof后面没有单独出现a,也没有取地址,所以代表的是首元素地址,所以是4/8,根据平台的不同而决定大小 printf("%d", sizeof(*a));//1 //这里的a代表的是首元素地址,然后对其进行解引用,所以代表的是首元素,即一个字符的大小,所以结果是1 printf("%d", sizeof(a[1]));//1 //这里就是计算数组元素的大小,所以结果是1 printf("%d", sizeof(&a));//4 //这里对数组名取地址,取得是整个数组的地址,地址的大小是4/8 printf("%d", sizeof(&a+1));//4 //这里对数组名取地址,然后+1跳过一个同类型数组大小的地址,所代表的也是一个地址,所以结果是4/8 printf("%d", sizeof(&a[0]+1));//4 return 0; }
这里所讲解的也是数组名在不同地方所代表的含义
#define _CRT_SECURE_NO_WARNINGS #includeint main() { char a[] = "abcdef"; //strlen是计算字符串的大小,所以关注的是 的位置,遇到 即会停止 //而sizeof关注的是占用内存空间的大小,不在乎内存放的是什么 printf("%d", strlen(a));//6 printf("%d", strlen(a+0));//6 printf("%d", strlen(*a));//报错 printf("%d", strlen(a[1]));//报错 printf("%d", strlen(&a));//6 printf("%d", strlen(&a+1));//随机值 //这里的结果是随机值的原因是,&a代表的是整个数组的地址,+1跳过的是整个数组的地址大小,所以指向了一个新地址,所以结果是随机值 printf("%d", strlen(&a[0]+1));//5 return 0; }
#define _CRT_SECURE_NO_WARNINGS #includeint main() { char *p = "abcdef"; //strlen是计算字符串的大小,所以关注的是 的位置,遇到 即会停止 //而sizeof关注的是占用内存空间的大小,不在乎内存放的是什么 printf("%d", sizeof(p)); //这里的p是一个指针,指针的大小就是4/8 printf("%d", sizeof(p +1)); //这里的p是一个地址,所以+1,也还是个地址,结果是4/8 printf("%d", sizeof(*p)); //这里是对数组的首元素解引用,所以结果是1 printf("%d", sizeof(p[1])); //字符元素的大小是一个字节,所以结果是1 printf("%d", sizeof(&p)); //这里是对p进行取地址,地址的大小是4/8 printf("%d", sizeof(&p +1)); //这里的对p取地址,p是一个指针,对指针进行取地址,所以是二级指针,所以+1跳过的是p的大小的字节之后的地址,地址大小是4/8 return 0; }
#define _CRT_SECURE_NO_WARNINGS #includeint main() { char *p = "abcdef"; printf("%d", strlen(p)); //这里的p指向的是数组的首元素,所以结果是6 printf("%d", strlen(p+1)); //p+1指向的是数组的第二个元素,所以结果是5 printf("%d", strlen(*p)); //报错,strlen给的参数类型错误 printf("%d", strlen(p[0])); //同理,报错 printf("%d", strlen(&p)); //这里是对p取地址,这个地址不是数组的地址,所以是随机值 printf("%d", strlen(&p+1)); //同理这里是对p取地址,然后+1,这个不是数组的地址加1,这里的结果也是随机值,与上面的随机值没有联系 printf("%d", strlen(&p[0]+1)); //这里是对数组的首元素取地址,然后+1,所以是从第二个元素开始计算,结果5 return 0; }
#define _CRT_SECURE_NO_WARNINGS #includeint main() { int a[3][4] = { 0 }; printf("%dn", sizeof(a));//48 //这里sizeof后面单独出现数组名,代表的是整个数组,所以结果是48 printf("%dn", sizeof(a[0][0]));//4 //这里代表的就是数组的首元素,大小是4 printf("%dn", sizeof(a[0]));//16 //a[0]所代表的是这个二维数组的第一行,所以是a[0]是数组名 //sizeof后面单独出现数组名,所代表的含义是整个数组 //所以结果是16 printf("%dn", sizeof(a[0]+1));//4 //这里的a[0]表示的二维数组的第一个一维数组的首元素地址 //+1表示跳过一个整型指针大小的字节空间,指向的是下一个元素 //所以结果是4 printf("%dn", sizeof(*(a[0] + 1)));//4 //这里出现的a[0]代表的是二维数组的第一个一维数组,代表的是第一行的首元素地址 //+1代表的是第一样首元素的地址跳到下一个元素的地址 //对其解引用,所以*((a[0]+1)) -----> a[0][1] printf("%dn", sizeof(a+1));//4 //这里的a表示的是二维数组的首元素地址,也就是a[0], //+1表示跳到a[1]的地址 //地址也就是指针,所以大小是4 printf("%dn", sizeof(*(a + 1)));//16 //这里的a代表的是二维数组首元素a[0]的地址 //+1代表的是a[1]的地址 //对a[1]解引用就相当于---->sizeof(a[1]) //所以结果是16 printf("%dn", sizeof(&a[0]+1));//4 //这里的对a[0]取地址,所以指向的是二维数组的第一个一维数组 //+1就是跳过一个数组指针大小的字节空间 //得到的是第二行的地址 //地址的大小是4 printf("%dn", sizeof(*(&a[0] + 1)));//16 //这里对a[0]取地址,就是指向二维数组的第一个一维数组 //+1就是跳过一个数组指针的大小的字节空间 //所以指向的是二维数组的第二个一维数组 //所以是整个数组解引用,大小是16 printf("%dn", sizeof(*a));//16 //这里的a是表示二维数组的首元素a[0] //对a[0]接引用就相当于sizeof(a[0]) //所以结果是16 printf("%dn", sizeof(a[3]));//16 //这里a[3]表示的是数组的第4个一维数组,所以大小是16 //这里并不是对a[3]内存空间的访问,所以不存在越界的问题 return 0; }
#include指针的指向问题int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; } struct Test { int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; }* p = (struct Test*)0x100000; //假设p 的值为0x100000。 如下表表达式的值分别为多少? //已知,结构体Test类型的变量大小是20个字节 //x86 int main() { printf("%pn", p + 0x1); //0x100000+20-->0x100014 //0x1代表的是+1,结构体指针的大小是20个字节,所以+1就是+20 //在16进制中,20的表达形式是14 printf("%pn", (unsigned long)p + 0x1); //1,048,576+1 --> 1,048,577 //这里进行强制类型转换,变成整型,+1就是整型转换后的值+1 //0x100001 printf("%pn", (unsigned int*)p + 0x1); //这里是指针类型+1,就是加4个字节 //0x100000+4-->0x100004 return 0; }
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1);
//这里对a取地址,就是整个数组的地址,然后+1
int* ptr2 = (int*)((int)a + 1);
//这里是首元素的地址化为整型,然后+1
//假设首元素的地址是0x0012ff40,那么这个整数加1就变成了0x0012ff41
//然后指针解引用就变成了2000000
printf("%x,%x", ptr1[-1], *ptr2);
//ptr1[-1]---->*(ptr1+(-1))
//这里的ptr是一个int*类型的大小,所以占4个字节的空间
return 0;
}
解析如下
#includeint main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int* p; p = a[0]; printf("%d", p[0]); return 0; }
解析:
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf("%p,%dn", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
解析如下
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%sn", **++cpp);
printf("%sn", *-- * ++cpp + 3);
printf("%sn", *cpp[-2] + 3);
printf("%sn", cpp[-1][-1] + 1);
return 0;
}
上面解析的大小写问题请忽略,重在对结果的分析



