【C语言】指针数组测试题(1万字长文)(上)

简介: 【C语言】指针数组测试题(1万字长文)

江南可采莲,莲叶何田田。鱼戏莲叶间。鱼戏莲叶东,鱼戏莲叶西,鱼戏莲叶南,鱼戏莲叶北。 — 两汉·汉乐府《江南》

这篇博客我们将会讲解一些习题,习题是有关于数组和指针的,数组方面的习题也能帮助我们更好的理解sizeof和strlen,指针的习题也全方位锻炼我们对指针的理解。

一维数组🍀

//一维数组
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(a):sizeof中如果放的是数组名,则为求整个数组的大小,所以应该是16
  • sizeof(a+0):sizeof()中放的是a+0,也就是首数组名+0,数组名+0得到数组首元素的地址,所以这里是求地址的大小,在32位下是4,在64位下是8。
  • sizeof(*a):*a代表着,a地址的元素,这个元素的类型是int,所以大小为4。
  • sizeof(a+1):与第二个差不多,a+1得到第二个元素的地址,求地址的大小在32位下是4,在64位下是8。
  • sizeof(a[1]):a[1]就是第二个元素,第二个元素的类型是int,所以结果是4
  • sizeof(&a):&a的地址实际上就是取出整个数组的地址,但是也还是地址,所以在32位下是4,在64位下是8。
  • sizeof(*&a):上面一题我们知道&a是取出整个数组的地址,但是这里又多了一个 *,就相当于先取地址然后再解引用,两个相互抵消了。还有一种理解就是数组整个地址的解引用就相当于是整个数组(sizeof(a)),所以是16
  • sizeof(&a+1):这里其实是也有一个知识点就是,&(取地址)操作符是比+号(不是正号)这个操作符的优先级要高的,所以就相当于拿到整个数组的地址再+1,就跳过一个数组的长度。但还是地址,大小在32位下是4,在64位下是8。
  • sizeof(&a[0]):我们知道[]的优先级是高于&的,就是相当于取出第一个元素的地址然后&,但是也还是地址,是地址的话大小在32位下是4,在64位下是8。
  • sizeof(&a[0]+1):跟上面可以说是一个的就只是地址加了1,是地址的话大小在32位下是4,在64位下是8。

字符数组🐽

接下来是字符数组

int main()
{
  //字符数组
  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));
}

解析

  • sizeof(arr):还是老规矩,sizeof内放数组名求的是数组整个的大小,数组里放的是全是字符而不是字符串,所以一共6个字符,一共字符大小为1字节最终结果就是6。
  • sizeof(arr + 0):这里放的就不是一个单纯的数组名了,而是一个首地址+0,还是首地址,是地址那么在32位下就是4,64位下就是8。
  • sizeof(*arr):这个也不是单纯的一个数组名,数组名代表的是首元素地址,首元素地址解引用得到的就是首元素,首元素的类型是char,那么大小就为1。
  • sizeof(arr[1]):arr[1]就代表第二个元素,那么大小就是1。
  • sizeof(&arr)):&取出的还是地址,是地址那么在32位下就是4,64位下就是8
  • sizeof(&arr + 1):依然还是地址,是地址那么在32位下就是4,64位下就是8
  • sizeof(&arr[0] + 1):&arr[0],就是取出第一个元素的地址,第一个元素的地址+1,也是地址,是地址那么在32位下就是4,64位下就是8
    ![](https://ucc.alicdn.com/images/user-upload-01/ad284c62187445d78ed8e58493e03c7b.png)

来看看strlen

int main()
{
char arr[] = {'a','b','c','d','e','f'};
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(arr):我们知道strlen是求字符串长度的,返回从参数的地址到\0之间的字符个数,但是我们的数组里面放的是字符并不是字符串,那怎么办呢?其实\0的ASCII码值就是0(字符'0'的是48),也就是说strlen会从数组首元素地址开始从内存中找0,但我们是不知道什么时候能找到的,所以是一个随机值
  • strlen(arr+0):与上面的是一致的都是首元素地址。是一个随机值。
  • strlen(*arr)这里就有得一说了,我们知道strlen里一般放的都是字符数组的地址,而这里*arr就相当于arr[0],而’a’代表的ASCII码是97,这里又是什么意思呢?也就说strlen是要从地址97开始往后找0,但是我们的操作系统有一个规定在大多数操作系统中,0到某个特定值之间的地址被保留给内核使用,称为内核地址空间。这个特定值可以因操作系统和硬件架构而异,但通常是一个较低的地址。所以这里就会出现野指针,这是一行错误代码。error
  • strlen(arr[1]):与上一个一致是error。
  • strlen(&arr):&arr和arr在地址的值上都是一样的所以也是随机值。并且这两个随机值是相当的。
  • strlen(&arr+1):还是地址,但是+1了,应该是随机值-1。吗?,注意这里是&arr,我们知道&arr的类型数组指针,也就是要跳过一个数组,所以这里一个是随机值-6
  • strlen(&arr[0]+1):仍然是首元素地址+1,由于这里是取出元素的地址,所以+1是跳过一个字节,还是随机值-1
    最后两个的细节要注意,不要只知道无法运行。

接下来就是字符串了。

int main()
{
  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));
}
  • sizeof(arr):我们知道字符串末尾其实有一个’\0’,它也是要占一个字节的。所以这个数组的总大小就是7。
  • sizeof(arr + 0):现在不是只有数组名了,而arr+0就代表着首元素地址,是地址32位下是4,64位下是8。
  • sizeof(*arr):首元素地址解引用得到首元素,首元素类型为char,所以大小为1。
  • sizeof(arr[1]):第二个元素的地址解引用得到的是第二个元素,同上大小为1。
  • sizeof(&arr):取出arr整个数组的地址,但是在数值上就是首元素地址,是地址32位下是4,64位下是8。
  • sizeof(&arr + 1):&arr+1,就是地址跳过一个数组大小,还是地址,是地址32位下是4,64位下是8。
  • sizeof(&arr[0] + 1):注意这里是+1的类型与上面不同这里是&arr[0],也就是说+1加一个元素。是地址32位下是4,64位下是8。
char arr[] = "abcdef";
    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的。

  • strlen(arr):是标准的用法,这里属于是字符串而不是字符,从首元素到\0之前的元素是abcdef,一共6个,也就是说字符串长度为6。
  • strlen(arr + 0):同上一样是首元素地址,没有太大区别。6。
  • strlen(arr)):这里arr就相当于arr[0],而’a’代表的ASCII码是97,这里又是什么意思呢?也就说strlen是要从地址97开始往后找0,但是我们的操作系统有一个规定**:在大多数操作系统中,0到某个特定值之间的地址被保留给内核使用,称为内核地址空间。这个特定值可以因操作系统和硬件架构而异,但通常是一个较低的地址。所以这里就会出现野指针,这是一行错误代码。error
  • strlen(arr[1]):是’b’同上。error。
  • strlen(&arr):取地址数组名,就是首元素地址,从首元素地址到\0,长度是6个字节。
    -strlen(&arr + 1):这个就有点不一样了,&arr就是取出整个数组的地址,整个数组地址的类型是数组指针,数组指针+1一个跳过一个数组大小,所以这个是随机值。
    strlen(&arr[0] + 1):还是老生常谈的问题,&arr[0]就是首元素地址,首元素地址可以看出类型就是char *类型,char *类型+1也只是跳过一个字节。所以跳过了’a’,剩下的长度就是5。

然后来看看指针与字符串结合。

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));
  • sizeof ( p):注意这里并不是数组了,而是指针指向内存中存储的一个字符串,p存储字符串的首字符地址,是地址那么在32位下是4,64位下是8。
  • sizeof(p+1):这里与上面基本一致,不过是第二个字符的地址,是地址那么在32位下是4,64位下是8。
  • sizeof(*p):p是字符串首字符地址,然后 * p就是拿到首字符,首字符的类型是char,故大小为1。
  • sizeof(p[0]):和上面一样都是首字符,首字符的类型是char,故大小为1。
  • sizeof(&p):取出p变量的地址,还是地址,是地址那么在32位下是4,64位下是8。
  • sizeof(&p+1):取出p的地址再+1,由于p的类型是char *,+1也只是+1字节,但是归根到底还是地址,是地址那么在32位下是4,64位下是8。
  • sizeof(&p[0]+1):任然是地址,是地址那么在32位下是4,64位下是8。

char *p = "abcdef";
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));
  • strlen( p):p中存储的是这个字符串的首字符地址,那么从首字符到\0之前有6个字符,字符串长度为6。
  • strlen(p+1):p+1,变成是第二个字符的地址,从第二个字符到\0之前有5个字符,长度为5。
  • strlen(p): * p就是拿到’a’的ASCII码97,也就说strlen是要从地址97开始往后找0,但是我们的操作系统有一个规定*:在大多数操作系统中,0到某个特定值之间的地址被保留给内核使用,称为内核地址空间。这个特定值可以因操作系统和硬件架构而异,但通常是一个较低的地址。所以这里就会出现野指针,这是一行错误代码。error
  • strlen(p[0]):与上面一致,都是访问低地址而出现野指针error。
  • strlen(&p):注意这里是取出p的地址,并不是p中存储的地址,是有很大区别的,p中的地址是字符串首字符的,p的地址是p在内存中存储的。所以这里是随机值。
  • strlen(&p+1):与上面基本一致,这里是&p+1,这里&p可以看成是整个字符串,+1就是跳过整个字符串。这里也肯定会出现随机值,但是不一样就会与上面这个题的随机值一样。
  • strlen(&p[0]+1):我们知道*(p+0) = p[0],而p变量存储的地址是字符串首字符的,相当于拿到首字符了已经,再取地址就是首字符地址,再+1也就跳过首字符,从第二个字符到\0之前有5个字符,长度为5。


目录
相关文章
|
15天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
69 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
15天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
43 9
|
15天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
40 7
|
15天前
|
传感器 算法 安全
【C语言】两个数组比较详解
比较两个数组在C语言中有多种实现方法,选择合适的方法取决于具体的应用场景和性能要求。从逐元素比较到使用`memcmp`函数,再到指针优化,每种方法都有其优点和适用范围。在嵌入式系统中,考虑性能和资源限制尤为重要。通过合理选择和优化,可以有效提高程序的运行效率和可靠性。
56 6
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
19天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
19天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
61 3
|
20天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
18天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
46 1
|
19天前
|
存储 算法 C语言
用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容
本文探讨了用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容,旨在为开发者提供全面的指导和灵感。
35 2