写点什么

C 语言数组与指针练习题(原题 + 解析 + 原码)

作者:未见花闻
  • 2022 年 6 月 21 日
  • 本文字数:6256 字

    阅读完需:约 21 分钟

🍃 1.数组试题

🍂1.1 一维数组题组

下面程序会输出什么结果?


//一维数组int a[] = {1,2,3,4};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a+0));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(a[1]));printf("%d\n",sizeof(&a));printf("%d\n",sizeof(*&a));printf("%d\n",sizeof(&a+1));printf("%d\n",sizeof(&a[0]));printf("%d\n",sizeof(&a[0]+1));
复制代码


我们都知道sizeof是用来求某一数据类型所占内存的大小,其中单位为字节。对于指针类型的大小在 32 位平台上占 4 个字节,64 位平台占 8 字节。数组名一般情况下指数组首元素的地址,但是有例外,也就是二般情况:使用sizeof(数组名)计算数组名大小,计算的是整个数组的大小;&数组名指的的是数组指针,对其进行+1运算会跳过整个数组,比如 int arr = {1,2,3,4,5},&arr = 00000001&arr + 1 = 00000021


int a[] = {1,2,3,4};//数组类型为intprintf("%d\n",sizeof(a));//sizeof计算数组名得整个数组大小,16printf("%d\n",sizeof(a+0));//对数组名做运算,属于一般情况,为指针,4 or 8printf("%d\n",sizeof(*a));//解引用数组名,数组名为首元素地址,解引用得元素,该数组元素类型为int,大小为4printf("%d\n",sizeof(a+1));//对数组名做运算,属于一般情况,为指针,4 or 8printf("%d\n",sizeof(a[1]));//数组第二个元素,类型是int,4printf("%d\n",sizeof(&a));//数组指针,4 or 8printf("%d\n",sizeof(*&a));//解引用数组指针,指向整个数组,16printf("%d\n",sizeof(&a+1));//数组指针进行加法运算还是指针,4 or 8printf("%d\n",sizeof(&a[0]));//取第一个元素地址,指针,4 or 8printf("%d\n",sizeof(&a[0]+1));//指针加法运算还是指针,4 or 8
复制代码

🍂1.2 字符数组题组

🌿1.2.1 不含’\0’题组

下面程序会输出什么?


char arr[] = {'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr+0));printf("%d\n", strlen(*arr));printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr+1));printf("%d\n", strlen(&arr[0]+1));
复制代码


下面再来聊一聊strlen,该函数为 C 语言中一库函数,用来计算字符串中字符的个数,参数为字符指针,它是根据\0为结束标志,如果一个字符数组中不含\0则会越出数组地址,直到读到\0为止才结束。字符串默认最后带一个\0


//字符数组char arr[] = {'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));//计算数组名大小表示整个数组,6printf("%d\n", sizeof(arr+0));//数组名加减运算为指针,4 or 8printf("%d\n", sizeof(*arr));//解引用数组名,表示第一个元素,1printf("%d\n", sizeof(arr[1]));//第二个元素,1printf("%d\n", sizeof(&arr));//数组指针,4 or 8printf("%d\n", sizeof(&arr+1));//数组指针运算还为指针,4 or 8printf("%d\n", sizeof(&arr[0]+1));//取第二个元素地址为指针,进行运算仍然为指针,4 or 8printf("%d\n", strlen(arr));//无\0结尾,随机值printf("%d\n", strlen(arr+0));//无\0结尾,随机值printf("%d\n", strlen(*arr));//strlen需要传入的参数为指针,实际传入字符,会以ASCII码为地址开始访问,非法访问,不正确printf("%d\n", strlen(arr[1]));//同上printf("%d\n", strlen(&arr));//传入参数类型冲突,需要字符指针,实际传入数组指针,就算传参成功,无\0,为随机值printf("%d\n", strlen(&arr+1));//传入参数类型冲突,需要字符指针,实际传入数组指针,就算传参成功,无\0,为随机值printf("%d\n", strlen(&arr[0]+1));//指针运算仍为指针,无\0结尾,随机值
复制代码

🌿1.2.2 含’\0’题组

下列程序会输出什么?


char arr[] = "abcdef";printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr+0));printf("%d\n", strlen(*arr));printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr+1));printf("%d\n", strlen(&arr[0]+1));char *p = "abcdef";printf("%d\n", sizeof(p));printf("%d\n", sizeof(p+1));printf("%d\n", sizeof(*p));printf("%d\n", sizeof(p[0]));printf("%d\n", sizeof(&p));printf("%d\n", sizeof(&p+1));printf("%d\n", sizeof(&p[0]+1));printf("%d\n", strlen(p));printf("%d\n", strlen(p+1));printf("%d\n", strlen(*p));printf("%d\n", strlen(p[0]));printf("%d\n", strlen(&p));printf("%d\n", strlen(&p+1));printf("%d\n", strlen(&p[0]+1));
复制代码


数组指针变量笔试题组解答


char arr[] = "abcdef";printf("%d\n", sizeof(arr));//表示整个数组大小,数组中含有6个字符与1个\0,大小为7printf("%d\n", sizeof(arr+0));//表示指针,4 or 8printf("%d\n", sizeof(*arr));//解引用指向字符,大小为1printf("%d\n", sizeof(arr[1]));//表示第二个元素,1printf("%d\n", sizeof(&arr));//数组指针,4 or 8printf("%d\n", sizeof(&arr+1));//数组指针加减运算仍为指针,4 or 8printf("%d\n", sizeof(&arr[0]+1));//指针,4 or 8printf("%d\n", strlen(arr));//首元素地址开始计数,字符串末尾含\0,6printf("%d\n", strlen(arr+0));//首元素地址开始计数,字符串含\0,6printf("%d\n", strlen(*arr));//指向第一个字符元素,以这个字符的ASCII码为地址进行访问,是非法的,不正确printf("%d\n", strlen(arr[1]));//表示第二个字符元素,理由同上,不正确printf("%d\n", strlen(&arr));//strlen需要传入字符指针参数,实际传入数组指针,传入指针类型不同,如果传参成功,大小为6printf("%d\n", strlen(&arr+1));//strlen需要传入字符指针参数,实际传入数组指针,数组指针加1跳过整个数组,传入指针类型不同,如果传参成功,大小为随机值printf("%d\n", strlen(&arr[0]+1));//表示第二个元素地址,大小为5
复制代码


字符指针常量笔试题组解答


char *p = "abcdef";printf("%d\n", sizeof(p));//字符指针,4 or 8printf("%d\n", sizeof(p+1));//字符指针,4 or 8printf("%d\n", sizeof(*p));//指向字符串第一个字符,1printf("%d\n", sizeof(p[0]));//同上,1printf("%d\n", sizeof(&p));//指向该字符指针的地址的指针。4 or 8printf("%d\n", sizeof(&p+1));//指针, 4 or 8printf("%d\n", sizeof(&p[0]+1));//该字符串第二个字符的地址,4 or 8printf("%d\n", strlen(p));//传入地址为第一个元素地址该字符串末尾有\0,长度为6printf("%d\n", strlen(p+1));//传入地址为第二个元素地址该字符串末尾有\0,长度为5printf("%d\n", strlen(*p));//传入第一个字符的ASCII码,非法访问,不正确printf("%d\n", strlen(p[0]));//同上,不正确printf("%d\n", strlen(&p));//传入指针为字符指针的地址,随机值printf("%d\n", strlen(&p+1));//同上,随机值printf("%d\n", strlen(&p[0]+1));//传入参数表示第二个元素的地址,字符串末尾有\0,长度为5
复制代码

🍂1.3 二维数组题组

下列程序会输出什么?


//二维数组int a[3][4] = {0};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a[0][0]));printf("%d\n",sizeof(a[0]));printf("%d\n",sizeof(a[0]+1));printf("%d\n",sizeof(*(a[0]+1)));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(*(a+1)));printf("%d\n",sizeof(&a[0]+1));printf("%d\n",sizeof(*(&a[0]+1)));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a[3]));
复制代码


在解答这道题目之前,我们来聊一聊二维数组!其实二维数组是由一个个相同元素个数一维数组组成,并且每个一维数组在内存中的储存是连续的。为了便于我们人类思维的理解就把二维数组当做矩阵的形式进行理解,也就是说二维数组是由几行连续一维数组组成,这几个一位数组的地址是连续的。对于二维数组的数组名可以类比于一维数组进行学习!💡二维数组的数组名:在一维数组中数组名一般表示首元素的地址,而二维数组的数组名一般表示首行元素的首地址,比如一个 3*3 的二维数组arr*arr表示第一行的一维数组,也相当于一维数组的数组名,*(arr + 1)表示第二行以此类推。同理二维数组与一维数组一样,有二般情况,sizeof(二维数组名)中的数组名表示整个二维数组;&arr得到的是二维数组指针,加1跳过整个二维数组,和一维数组非常类似。



//二维数组int a[3][4] = {0};printf("%d\n",sizeof(a));//表示整个二维数组大小,3*4*4 = 48printf("%d\n",sizeof(a[0][0]));//表示第一行第一列的元素,4printf("%d\n",sizeof(a[0]));//a[0]表示第一行一维数组的数组名,sizeof(数组名)表示整行数组大小,4*4 = 16printf("%d\n",sizeof(a[0]+1));//a[0]表示第一行一维数组的数组名,加1表示第一行第二个元素地址,4 or 8printf("%d\n",sizeof(*(a[0]+1)));//表示第一行第二个元素,4printf("%d\n",sizeof(a+1));//表示第二行一维数组首地址,4 or 8printf("%d\n",sizeof(*(a+1)));//*(a+1)表示第二行一维数组数组名,sizeof(数组名)表示整行数组大小,4*4 = 16printf("%d\n",sizeof(&a[0]+1));//a[0]表示第一行一维数组数组名,在对其取地址的第一行一维数组首地址,类型为数组指针,加1表示第二行一维数组首地址,4 or 8printf("%d\n",sizeof(*(&a[0]+1)));//&a[0]+1表示第二行一维数组首地址,解引用它表示第二行一维数组数组名,4*4 = 16printf("%d\n",sizeof(*a));//表示第一行一维数组数组名,4*4 = 16printf("%d\n",sizeof(a[3]));//表示第四行一维数组数组名(实际上并没有访问第四行的元素,所以并不算数组越界),4*4 = 16
复制代码

🍃 2.指针试题

🍂2.1 指针题 1

int main(){    int a[5] = { 1, 2, 3, 4, 5 };    int *ptr = (int *)(&a + 1);    printf( "%d,%d", *(a + 1), *(ptr - 1));    return 0; }//程序的结果是什么?
复制代码


&a为数组指针,加 1 跳过整个数组,强制转换int*再减 1 得最后一个数组元素的地址。*(a+1)表示数组第二个元素,因此程序会输出2,5


2,5D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 25604)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.2 指针题 2

//告知结构体的大小是20个字节struct Test{ int Num; char *pcName; short sDate; char cha[2]; short sBa[4];}*p;//假设p 的值为0x100000。 如下表表达式的值分别为多少?//已知,结构体Test类型的变量大小是20个字节int main(){ p = 0x100000; printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0; }
复制代码


结构体大小已经告知为 20 字节,结构体指针为p = 0x100000p+0x1相当于对结构体指针加 1,会跳过整个结构体,地址会增加 20,以 16 进制输出结果为00100014。将结构体指针p强制转换成unsigned long,加 1 就是普通运算的加 1,16 进制结果为00100001。将结构体指针p强制转换为unsigned int*,加 1 跳过 4 个字节,16 进制结果为00100004。所以程序会输出:001000140010000100100004。


001000140010000100100004
D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 30036)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.3 指针题 3

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; }
复制代码


&a+1表示数组最后一个元素的后一个元素的地址,强制转换为int*并将其赋值给ptr1,prt1[-1]就是数组最后一个元素4。先将a强制转换为int再加 1,因为地址编号本身就是整数,这种情况下加 1 地址编号会加 1,然后强制转换为int*,将其赋值给ptr2,在解引用之前,我们先来梳理一下这个数组内存中的储存情况(16 进制),由于大小端,情况会有所不同,这里统一小端为例:低地址 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 高地址原来指向 01,强制转换int加 1 在转int*,该指针会指向第一个 00,对其解引用,所指向内存情况为 00 00 00 02,输出结果为2000000


4,2000000D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 22716)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.4 指针题 4

#include <stdio.h>int main(){    int a[3][2] = { (0, 1), (2, 3), (4, 5) };    int *p;    p = a[0];    printf( "%d", p[0]); return 0; }
复制代码


这道题不难,就是有一个小坑,就是容易把(0,1)看成{0,1},根据逗号运算符运算规则,取逗号后一个元素,这个数组也可以简化成{{1,3}, {5,0}, {0,0}},p[0]相当于a[0][0],即第一行第一个元素,就是1


1D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 12624)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.5 指针题 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]);    return 0; }
复制代码



&p[4][2] - &a[4][2] ,以%p以 %p 输出得 16 进制元素个数差(补码形式),%d 输出得之间元素个数差!由内存图,&p[4][2] - &a[4][2] 中间元素个数差为-4,转 16 进制补码FFFFFFFC


FFFFFFFC,-4
D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 33716)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.6 指针题 6

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指整个数组后一个地址,解引用前一个地址ptr1 - 1表示数组最后一个元素10*(aa+1)为第二行首个元素地址,解引用前一个地址ptr2 - 2表示数组第一行最后一个元素5


10,5D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 30500)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.7 指针题 7

#include <stdio.h>int main(){ char *a[] = {"work","at","alibaba"}; char**pa = a; pa++; printf("%s\n", *pa); return 0; }
复制代码


pa为数组首元素地址,pa++指向数组第二个元素,解引用并以%s格式输出得at


at
D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 30204)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码

🍂2.8 指针题 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); printf("%s\n", *--*++cpp+3); printf("%s\n", *cpp[-2]+3); printf("%s\n", cpp[-1][-1]+1); return 0; }
复制代码


这道题需要很细心,要注意自增自减运算符会使变量的值发生改变!注:c 数组里面存的是各字符串的指针!






POINTERSTEW
D:\gtee\C-learning-code-and-project\test_916\Debug\test_916.exe (进程 24688)已退出,代码为 0。按任意键关闭此窗口. . .
复制代码


发布于: 刚刚阅读数: 4
用户头像

未见花闻

关注

还未添加个人签名 2021.11.15 加入

还未添加个人简介

评论

发布
暂无评论
C语言数组与指针练习题(原题+解析+原码)_6月月更_未见花闻_InfoQ写作社区