一维数组
int main()
{
int a[]={
1,2,3,4};
printf("%d\n",sizeof(a));//16
printf("%d\n",sizeof(a+0));//16(第一次的答案) -4 数组名这里表示首元素地址,a+0还是首元素地址
printf("%d\n",sizeof(*a));//4
printf("%d\n",sizeof(a+1));//4
printf("%d\n",sizeof(a[1]));//4
printf("%d\n",sizeof(&a));//16 -4 &a取出的是数组的地址,但是数组的地址也是地址,答案4
printf("%d\n",sizeof(*&a));//4 -16 &a是数组的地址,数组的地址解引用访问的数组,sizeof计算就是数组的大小
printf("%d\n",sizeof(&a+1));//1 -4 &a+1也是一个地址,跳过了一个数组。
printf("%d\n",sizeof(&a[0]));//4
printf("%d\n",sizeof(&a[0]+1));//4
return 0;
}
字符串
int main()
{
char arr[]={
'a','b','c','d','e','f'};
printf("%d\n",sizeof(arr));//7 -6//sizeof计算的是数组大小,6*1=6字节
printf("%d\n",sizeof(arr+0));//1 -4//首元素地址
printf("%d\n",sizeof(*arr));//1
printf("%d\n",sizeof(arr[1]));//1
printf("%d\n",sizeof(&arr));//4
printf("%d\n",sizeof(&arr+1));//4
printf("%d\n",sizeof(&arr[0]+1));//4
printf("%d\n",strlen(arr));//6 //随机值,stelen需要遇到\0才停止计数
printf("%d\n",strlen(arr+0));//1 //随机值
//printf("%d\n",strlen(*arr));//err strlen(地址) *arr 首元素'a' a的ASCII的值为97,strlen就会将97作为地址,进行访问,此时已经非法访问了
//printf("%d\n",strlen(arr[1]));//err
//printf("%d\n",strlen(&arr));// 随机值
//printf("%d\n",strlen(&arr+1));// 随机值-6
printf("%d\n",strlen(&arr[0]+1));//1 //随机值-1
return 0;
}
int main()
{
char arr[]="abcdef";
printf("%d\n",sizeof(arr));//6 -7 sizeof计算的数组大小,单位是字节:7
printf("%d\n",sizeof(arr+0));//4 计算是地址的大小-arr,0是首元素地址
printf("%d\n",sizeof(*arr));//1 *arr是首元素,sizeof(*arr)计算首元素的大小
printf("%d\n",sizeof(arr[1]));//1 arr[1]是第二个元素,sizeof(arr[1])计算第二个元素的大小
printf("%d\n",sizeof(&arr));//4 &arr虽然是数组的地址,但也是地址,大小是4/8字节
printf("%d\n",sizeof(&arr+1));//4 &arr+1是跳过整个数组的地址,但也是地址
printf("%d\n",sizeof(&arr[0]+1));//4 &arr[0]+1是第二个元素的地址
printf("%d\n",strlen(arr));//6
printf("%d\n",strlen(arr+0));//6
//printf("%d\n",strlen(*arr));//err
//printf("%d\n",strlen(arr[1]));//err
//printf("%d\n",strlen(&arr));//6 &arr 数组的地址-数组指针 char(*p)[7] =&arr; strlen的参数是const char*
//printf("%d\n",strlen(&arr+1));//随机值
printf("%d\n",strlen(&arr[0]+1));//5
return 0;
}
int main()
{
char *p="abcdef";
printf("%d\n",sizeof(p));//4 计算指针变量的大小
printf("%d\n",sizeof(p+1));//4 p+1得到的字符b的地址
printf("%d\n",sizeof(*p));//1 *p就是字符串的第一个字符--a
printf("%d\n",sizeof(p[0]));//1 p[0]==*(p+0) =='a'
printf("%d\n",sizeof(&p));//4 是取出p的地址,而不是计算数组的大小
printf("%d\n",sizeof(&p+1));//4 取出跳过一个p的地址
printf("%d\n",sizeof(&p[0]+1));//4 取出b的地址
printf("%d\n",strlen(p));//6
printf("%d\n",strlen(p+1));//5
printf("%d\n",strlen(*p));//err
printf("%d\n",strlen(p[0]));//err
printf("%d\n",strlen(&p));//随机值 取出的是p的地址,p后面\0位置不可知
printf("%d\n",strlen(&p+1));//随机值
printf("%d\n",strlen(&p[0]+1));//5 取出的b的地址
二维数组
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
printf("%d\n",sizeof(a[0]+1));//16 -4 a[0]是第一行数组名,数组名此时代表的是首元素地址,a[0]+1 是第二个元素地址
printf("%d\n",sizeof(*(a[0]+1)));//4
printf("%d\n",sizeof(a+1));//4 a是二维数组的数组名,没有sizeof(数组名),也没有&(数组名),所以a是首元素地址,而把二维数组看成一维数组时,二维数组的首元素就是它的第一行,a就是第一行地址,a+1就是第二行地址
printf("%d\n",sizeof(*(a+1)));//4 -16 *(a+1)就是对第二行解引用
printf("%d\n",sizeof(&a[0]+1));//4
printf("%d\n",sizeof(*(&a[0]+1)));//4 -16 &(数组名)代表是第一行数组的地址,&a[0]+1就是第二行地址,对其解引用就是对第二行解引用
printf("%d\n",sizeof(*a));//4 -16 a是首元素地址-第一行地址,*a就是第一行
printf("%d\n",sizeof(a[3]));//16
return 0;
}
看代码说结果:
int main()
{
int a[5] = {
1,2,3,4,5};
int *ptr = (int*)(&a+1);
printf("%d,%d", *(a+1),*(ptr-1));//2,5
return 0;
}
*(a+1),a是数组名,代表的是首元素的地址,a+1就是第二个元素的地址, * (a+1)就是第二个元素。
&a+1 ,&a是取出整个数组的地址,&a+1就是跳过一个数组,指向数组的后一个位置。ptr-1就是指向了数组最后一个元素,解引用得到了数组最后一个元素5
(因为a是数组,a的地址类型是char * 所以需要强制类型转化为 int * 才可以存储到ptr中。)
第二题
//假设p的值为0x100000,如下表达式的值分别为多少?
//已知结构体Test类型的变量大小为20个字节
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
printf("%p\n",p + 0x1);//0x100014 p是结构体指针,p+0x1 就是p+1,所以就是跳过一个结构体变量大小,就是跳过20个字节,十六进制就是0x100014
printf("%p\n",(unsigned long)p + 0x1);//0x100001 p的类型强制转化为(ungined long),p+1就是加上1。
printf("%p\n",(unsigned int*)p + 0x1);//0x100004 p的类型强制转化为(ungined int*),p+1就是跳过一个指针,大小是4
return 0;
}
第三题
int main()
{
int a[4] = {
1,2,3,4};
int *ptr1 = (int*)(&a+1);//
int *ptr2 = (int*)((int)a+1);//a作为数组名,在这个代表首元素地址,强制转化为int类型,a+1就是往后加一个字节数组内每一个元素都是4个字节,向后加一个字节,00 00 00 02 又因为内存是小端存储,所以以16进制打印,就为0x02000000
printf("%x,%x",ptr1[-1],*ptr2);//4 , 200000
return 0;
}
第四题
int main()
{
int a[3][2] = {
(0,1),(2,3),(4,5)};//!!!!注意数组内是(0,1)(2,3)(4,5)这是逗号表达式,逗号表达式的结果是最后一个表达式的结果,所以二维数组存的其实是 1 3 5 0 0 0
int *p;
p =a[0];//p拿到的是a[0] 也就是数组第一行的地址
printf("%d",p[0]);//1 p[0]就是第一行第一个元素
return 0;
}
第五题
int main()
{
int a[5][5];
int(*p)[4];
p = a;// p的类型为int(*)[4] a的类型为 int(*)[5] a强制赋值给p,p指向第一行第一个元素 &p[4][2]就是 *((*(p+4))+2) 地址相减就是中间元素的个数,又因为是低地址减去高地址,所以得出的结果是负数
printf("%p,%d\n",&p[4][2]-&a[4][2],&p[4][2]-&a[4][2]);// FFFFFFFC , -4
//-4的原码: 10000000000000000000000000000100
// 反码:11111111111111111111111111111011
// 补码: 1111 1111 1111 1111 1111 1111 1111 1100
// f f f f f f f c
return 0;
}
第六题
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));// 10,5
//&aa+1 跳过了一整个二维数组,ptr1-1 就指向了10
// *(aa+1) ,aa+1相当于aa[1],ptr2指向了6的地址,ptr2-1就指向5
return 0;
}
第七题
int main()
{
char *a[]={
"work","at","alibaba"};
char **pa = a;
pa++;
printf("&s\n",*pa);//"at"
return 0;
}
最复杂的一道题
int main()
{
char *c[] = {
"ENTER", "NEW", "POINT", "FIRST"};
char **cp[] = {
c+3, c+2, c+1, c};
char ***cpp = cp;
printf("%s\n",**++cpp);//POINT
printf("%s\n",*--*++cpp + 3);//ER
printf("%s\n", *cpp[-2] + 3);//ST
printf("%s\n", cpp[-1][-1]+1);//EW
return 0;
}