关于指针和数组的一些例题与解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 关于指针和数组的一些例题与解析

本章来了解一下关于指针和数组的一些例题,回顾之前所学的数组和指针,并作出一些总结。


1.一维数组


例题:

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a+0));//2
printf("%d\n",sizeof(*a));//3
printf("%d\n",sizeof(a+1));//4
printf("%d\n",sizeof(a[1]));//5
printf("%d\n",sizeof(&a));//6
printf("%d\n",sizeof(*&a));//7
printf("%d\n",sizeof(&a+1));//8
printf("%d\n",sizeof(&a[0]));//9
printf("%d\n",sizeof(&a[0]+1));//10


我们一个个分析:


第一个:我们首先知道a表示首元素的地址,只有两个情况下除外。

1.sizeof(数组名)

2.&数组名

而我们这里刚好是sizeof(数组名),那么它表示整个数组的元素,那么可以得到结果为16


第二个:

a + 0 b不是一个单独的数组名,所以它并不表示整个数组的元素,a表示首元素的地址,往后移0元素类型位,还是首元素的地址。那么可以得到结果为  4 / 8 。

得到4是因为在 ×86 的环境下 ,而得到 8 是在 × 64环境下。


第三个:


*a  表示取出首元素的地址,也就是1,1的类型为int 所以得到结果为4


第四个:


a表示首元素的地址,向后移一个元素的大小,得到的还是一个地址,那么结果还是4 / 8


第五个:


a[1]找到第二个元素,结果为4


第六个:


&a是一个地址,结果为 4 / 8


第七个:


先取出a的地址,得到了一串地址,在对地址解引用找到了a,相当于& 和 * 相互抵消了,得到的还是一个 a 任然表示整个数组的元素。我们可以认为 a  == *&a是一个东西。


第八个:


&a + 1,我们找到,这样是跳过了一整个数组,我们要是去访问的话是一定会越界的。但我们这里没有去访问后面的地址,只是在计算,它仍是个地址,所以结果为 4 / 8


第九个,第十个:


取出第一个元素的地址,是个地址,哪怕是再加上一个1,向后移动4个字节,也是一个地址,结果还是4 / 8.


2.字符数组


我们将分为两段解决

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));


我们首先来确认一下,这个数组有几个元素。答案是6个,千万别说7个,这里没有 /0 只有字符串中才有 /0。                                                                                                                                       我们根据上面所作出的一些解释可以很快知道第一个的答案:6,我就不再重复解释了。


第二个:地址向后移动0位还是一个地址,所以结果为 4 / 8。


第三个:*arr得到首元素,char为一个字节,结果为1。


第四个:与第三题一样,结果也是1。


第五个:&取出一个地址,结果为地址,所以得到4 / 8。


第六个:取出地址后向后移一个字节,还是地址,所以得到4 / 8。


第七个:与第六个只是表示不一样,但是表示的都是同一个东西,所以得到4 / 8。


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和sizeof并不是一个东西,sizeof是操作符,strlen是一个库函数,strlen只有遇到/0才停止。arr数组只有6个元素,其中并不包含/0。


那么对于第一个printf可以知道arr是首元素的地址,从首元素开始去找/0,这道题的结果是个随机数,我们并不知道/0究竟在什么地方。


第二个:同理,向后移动0个字符,结果也是个随机值


第三个:我们传进去了 '  a  '的ASCII码值,对应的是97,strlen去找对应97的地址处,强行计算它的大小。对于计算器给出的地址储存元素,都是由计算机来决定的,我们不能自己去抢地址来使用,有些地址我们是不能用的,所以这里会报错error。


第四个:和第一个的表达形式不同,也是取首元素的地址,结果也是个随机值。


第五个:哪怕移动了一个整个数组,也是个随机值,并且二者没有任何关系,谁都不知道/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));

这一段很简单,结合之前讲过的我们快速解决。

sizeof(arr)表示整个数组,数组共有六个元素结果为6.

第三、四个都是取出第一个元素,类型为char类型,结果为1。

剩下的都表示地址,结果均为 4 / 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只计算到/0之前的元素,所以第一个的结果为6。


第二个:向后移动了0个字节,还是第一个元素开始,结果依然为6。


第三个:把a传进去,相当于传97,又和上面一样,会报错。


第四个:将第二个元素b传进去了,也就是98,也会报错。


第五个:和第一个一样,传首元素,结果为6。


第六个:+1跳过了整个数组,所以结果是个随机数。


第六个:从第二个元素开始,结果为5。


三:二维数组


int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));//单独的sizeof(数组名)等于整个数组
  printf("%d\n", sizeof(a[0][0]));//表示二维数组的第一个元素,int类型
  printf("%d\n", sizeof(a[0]));//二维数组我们可以看成是由多一维数组组成
  //此时a[0],a[1]都是这一行的数组名,那么单独把数组名放在sizeof内部就是这一行的所有元素
  //那么结果就为16
  printf("%d\n", sizeof(a[0] + 1));//a[0]表示第一行首元素的地址,a[0] --> &a[0][0]—int*
  //a[0]+1 表示跳过一个字节,则为a[0][1]的地址
  printf("%d\n", sizeof(*(a[0] + 1)));//在上一题的基础上解引用,结果为一个元素类型int
    //答案为4
  printf("%d\n", sizeof(a + 1));//a表示首元素的地址,二维数组首元素的地址是第一行的地址
  //a+1 也就是第二行的地址,是地址结果就为4/8
  printf("%d\n", sizeof(*(a + 1)));//结合上一行进行解引用,找到的就是第二行,第二行的大小为16
  printf("%d\n", sizeof(&a[0] + 1));//&a[0]表示第一行的地址,+ 1就是第二行的地址
    //是地址就为4/8
  printf("%d\n", sizeof(*(&a[0] + 1)));//解引用拿到第二行,结果就为16
  printf("%d\n", sizeof(*a));//a表示首元素的地址,解引用拿到第一行,结果就为16
  printf("%d\n", sizeof(a[3]));//a[3]找到第四行,虽然超出了我们所定义的范围,但是sizeof
  //不会参与实际运算,也就不会去访问第四行,所以代码没有问题。
  //结果为16

总结:

数组名的意义:


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

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

3. 除此之外所有的数组名都表示首元素的地址。

相关文章
|
2月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
39 3
|
2月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
2月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
2月前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
2月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
16天前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
50 0
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
60 4
|
2月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
50 2
|
2月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
41 1
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
147 13

推荐镜像

更多