指针进阶(4)指针和数组笔试题解析 一维数组 字符数组 二维数组 指针 sizeof strlen 数组名

九、指针和数组笔试题解析

数组名:

通常是数组首元素地址但是有两个例外

1.sizeof(数组名),这里数组名表示整个数组,计算的是整个数组的大小

2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址

sizeof时一个操作符计算的是对象所占内存的大小,单位是字节,不在乎内存中存放的是什么只在乎内存大小

strlen是库函数,求字符串长度,从给定的地址向后访问字符,统计\0之前出现的字符个数

1.一维数组

int main()
{
   int a[] = {1,2,3,4};
   printf("%d\n",sizeof(a));
   //a表示整个数组,计算的是整个数组的大小4*4=16
   
   printf("%d\n",sizeof(a+0));
   //sizeof里不是数组名,a是数组首元素地址,a+0是1的地址,地址的大小4或8看几位平台
   
   printf("%d\n",sizeof(*a));
   //a表示数组首元素地址,*a表示数组的第一个元素,计算的是第一个元素的大小是4
   
   printf("%d\n",sizeof(a+1));
   //a表示数组首元素地址,a+1数组第二个元素地址,计算的是数组中第二个元素的地址的大小4或8

   printf("%d\n",sizeof(a[1]));
   //a[1]数组中的第二个元素,求第二个元素的大小4

   printf("%d\n",sizeof(&a));
   //&a取出的是数组的地址,数组的地址也是地址,是地址4或8字节

   printf("%d\n",sizeof(*&a));
   //&a取的是整个数组的地址,解引用得到的是整个数组,计算的是整个数组的大小4*4=16

   printf("%d\n",sizeof(&a+1));
   //&a取的是整个数组的地址,数组的地址+1跳过整个数组,还是地址大小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.字符数组

int main()
{
    char arr[] = {'a','b','c','d','e','f'};

    printf("%d\n", sizeof(arr));
    //计算的是整个数组的大小6*1=6

    printf("%d\n", sizeof(arr+0));
    //sizeof里不是数组名,arr是数组首元素地址,arr+0还是首元素地址,地址的大小4或8

    printf("%d\n", sizeof(*arr));
    //arr是首元素地址,解引用是首元素,首元素的大小是1

    printf("%d\n", sizeof(arr[1]));
    //arr[1]是数组第二个元素大小是1

    printf("%d\n", sizeof(&arr));
    //&arr是整个数组的地址,是地址4/8

    printf("%d\n", sizeof(&arr+1));
    //&arr是数组的地址,&arr+1是从数组的地址开始向后跳过了整个数组得到的地址还是地址,是地址4/8

    printf("%d\n", sizeof(&arr[0]+1));
    //&arr[0]是数组首元素地址,&arr[0]+1是数组第二个元素的地址是地址4/8
   
    printf("%d\n", strlen(arr));
    //arr是数组首元素地址,arr数组中没有'\0'strlen会继续向后找'\0'所以是随机值

    printf("%d\n", strlen(arr+0));
    //arr+0还是数组首元素地址,没有'\0',随机值

    printf("%d\n", strlen(*arr));
    //arr是首元素地址,*arr是数组的首元素,'a'的ASCII是97,97被当成地址从97向后数直到/0
    //可能非法访问,错误代码

    printf("%d\n", strlen(arr[1]));
    //arr[1]是'b',ASCII 98同上

    printf("%d\n", strlen(&arr));
    //&arr数组的地址和数组首元素地址相同,随机值

    printf("%d\n", strlen(&arr+1));
    //从数组后面开始数,随机值

    printf("%d\n", strlen(&arr[0]+1));
    //&arr[0]+1从第二个元素地址开始往后数,随机值

    char arr[] = "abcdef";//a b c d e f \0

    printf("%d\n", sizeof(arr));
    //计算的是整个数组的大小7

    printf("%d\n", sizeof(arr+0));
    //计算的是首元素的地址,是地址4/8

    printf("%d\n", sizeof(*arr));
    //*arr是数组首元素,计算a的大小为1

    printf("%d\n", sizeof(arr[1]));
    //arr[1]数组第二个元素大小为1

    printf("%d\n", sizeof(&arr));
    //&arr是数组的地址,是地址4/8

    printf("%d\n", sizeof(&arr+1));
    //&arr是数组的地址,数组的地址+1跳过整个数组是\0后面的地址,是地址4/8

    printf("%d\n", sizeof(&arr[0]+1));
    //&arr[0]是数组首元素地址+1是数组第二个元素地址,是地址4/8

    printf("%d\n", strlen(arr));
    //strlen统计\0之前的字符个数6

    printf("%d\n", strlen(arr+0));
    //从首元素向后数6

    printf("%d\n", strlen(*arr));
    //错误,传97非法访问

    printf("%d\n", strlen(arr[1]));
    //错误,传98非法访问

    printf("%d\n", strlen(&arr));
    //从首元素向后数6

    printf("%d\n", strlen(&arr+1));
    //从\0后面开始数,随机值

    printf("%d\n", strlen(&arr[0]+1));
    //从第二个元素地址向后数5

    char *p = "abcdef";a b c d e f \0
    //p里存放的是a的地址

    printf("%d\n", sizeof(p));
    //p里是地址,计算的是指针变量的大小4/8

    printf("%d\n", sizeof(p+1));
    //p+1是第二个元素的地址,是地址4/8

    printf("%d\n", sizeof(*p));
    //*p是首元素大小为1

    printf("%d\n", sizeof(p[0]));
    //p[0]是首元素大小为1

    printf("%d\n", sizeof(&p));
    //&p取的指针变量p的地址,是地址4/8

    printf("%d\n", sizeof(&p+1));
    //&p+1是跳过p之后的地址,是地址4/8

    printf("%d\n", sizeof(&p[0]+1));
    //&p[0]第一个元素的地址+1是第二个元素的地址,是地址4/8

    printf("%d\n", strlen(p));
    //p是首元素地址,从首元素开始数6

    printf("%d\n", strlen(p+1));
    //p+1是第二个元素地址,从第二个元素开始数5

    printf("%d\n", strlen(*p));
    //*p传的是a,97,非法访问,错误代码

    printf("%d\n", strlen(p[0]));
    //p[0]首元素a,97,非法访问,错误代码

    printf("%d\n", strlen(&p));
    //从p的地址开始向后数,随机值

    printf("%d\n", strlen(&p+1));
    //从跳过p的地址开始向后数随机值

    printf("%d\n", strlen(&p[0]+1));
    //从第二个元素开始向后数5

}

3.二维数组 

int main()
{
    int a[3][4] = {0};

    printf("%d\n",sizeof(a));
    //计算整个数组的大小3*4*4=48

    printf("%d\n",sizeof(a[0][0]));
    //第一行第一个元素大小4

    printf("%d\n",sizeof(a[0]));
    //第一行元素大小4*4=16

    printf("%d\n",sizeof(a[0]+1));
    //a[0]作为第一行数组名并没有单独放在sizeof内部a[0]是第一行第一个元素地址,a[0]+1是第一行第二个元素地址,是地址4/8

    printf("%d\n",sizeof(*(a[0]+1)));
    //第一行第二个元素4

    printf("%d\n",sizeof(a+1));
    //a表示首元素的地址,首元素地址就是第一行地址,a+1是第二行的地址,是地址4/8

    printf("%d\n",sizeof(*(a+1)));
    //第二行元素大小4*4=16

    printf("%d\n",sizeof(&a[0]+1));
    //第二行地址,是地址4/8

    printf("%d\n",sizeof(*(&a[0]+1)));
    //第二行元素大小4*4=16

    printf("%d\n",sizeof(*a));
    //第一行元素大小4*4=16

    printf("%d\n",sizeof(a[3]));
    //a[3]的类型是一行的数组名,一行数组名的大小是4*4=16

}

十、指针笔试题 

1.第一题

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf( "%d,%d", *(a + 1), *(ptr - 1));//2,5
}

2.第二题 

//结构体的大小是20个字节,x86环境
struct Test
{
 int Num;
 char *pcName;
 short sDate;
 char cha[2];
 short sBa[4];
}*p;
//已知,结构体Test类型的变量大小是20个字节
int main()
{
 p=(struct Test*)0x100000;
 printf("%p\n", p + 0x1);//00100014结构体指针+1跳过20字节换成16进制是14
 printf("%p\n", (unsigned long)p + 0x1);//00100001,p被强制类型转换成整型+1跳过1字节
 printf("%p\n", (unsigned int*)p + 0x1);//00100004,p被强制类型转换成整型指针+1跳过4字节
}

3.第三题 

int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int *ptr1 = (int *)(&a + 1);//ptr1[-1]等于*(ptr1-1)=4
    int *ptr2 = (int *)((int)a + 1);//首元素地址被转换成整型
    printf( "%x,%x", ptr1[-1], *ptr2);
    假设小端:01000000 02000000 03000000 04000000
    a被转换成整型+1再转换成整型指针相当于向后跳了1个字节再解引用访问4个字节
    00000002
    因为是小端所以打印02000000
}

4.第四题

int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式{1,3,5}
    int *p;
    p = a[0];
    printf( "%d", p[0]);//1
}

5.第五题 

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]);//FFFFFFFC -4
}

&p[4][2]等于*(*(p+4)+2)

p是整型指针+1跳过4字节

0123
                         p            p+1         p+2          p+3         p+4   地址由低到高

2位置前是*(*(p+4)+2),找到&a[4][2],指针-指针得到的是指针之间元素的个数,小地址-大地址得到-4

%d打印-4

%p打印-4

原码 10000000000000000000000000000100

反码 1111111111111111111111111111111111011

补码 1111111111111111111111111111111111100—>FFFFFFFC

6.第六题

int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int *ptr1 = (int *)(&aa + 1);//&aa+1跳过整个数组
    int *ptr2 = (int *)(*(aa + 1));//aa+1跳过一行
    printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10 5
}

7.第七题 

int main()
{
  char *a[] = {"work","at","alibaba"};//指针数组,把字符串首字符的地址存入
  char**pa = a;//a是指针数组首元素地址,pa是二级指针
  pa++;//pa++指向第二行首字符地址
  printf("%s\n", *pa);//解引用得到第二行首字符地址打印at
}

8.第八题

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);//**(cpp-2)+3 ST
  printf("%s\n", cpp[-1][-1]+1);//*(*(cpp-1)-1)+1 EW
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值