C语言例题讲解指针与数组

 更新时间:2022年07月07日 09:00:38   作者:龙兆万  
在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活

1.概要复习

本篇的内容主要围绕指针与数组、指针与字符串等之间的关系,以及进一步理解sizeof 、strlen 的使用与意义。

数组是指具有相同类型元素的集合,字符串常量是一个指向在连续空间里存放的字符的首字符的地址的指针。我们会在下面理解数组与字符串数组的不同。

sizeof 是一个操作符,是计算类型空间大小的。strlen 是针对字符串的库函数,用来求字符串的长度。

对于数组来说,数组名都是首元素地址,除了这两种情况外:

  • sizeof(数组名)——sizeof内部单独放置数组名表整个数组
  • &数组名——对数组名进行取地址操作表取出整个数组的地址

2.指针与数组笔试题

我们的目的是求下面各个 printf 语句输出什么。

2.1一维数组

#include <stdio.h>
int main()
{
	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));
	return 0;
}
#include <stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	//sizeof 内部单独放置数组名,计算整个数组的大小,结果为 4(int类型)*4(元素个数)=16
	printf("%d\n", sizeof(a + 0));
	//sizeof 内部没有单独放置数组名,此时数组名表首元素地址,a+0 依然表示首元素地址
	//故 sizeof 计算一个地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*a));
	//sizeof 内部没有单独放置数组名,此时数组名表首元素地址,*a 表对该地址解引用
	//即可得到 a 数组的第一个元素,大小为 4(int类型)
	printf("%d\n", sizeof(a + 1));
	//sizeof 内部没有单独放置数组名,此时数组名表首元素地址,a+1 表第二个元素地址
	//故 sizeof 计算一个地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(a[1]));
	//sizeof 内部没有单独放置数组名,a[1] 表数组的第二个元素,此写法可转置为 *(a+1)
	//即计算的结果是第二个元素的类型大小,即 4(int类型)
	printf("%d\n", sizeof(&a));
	//sizeof 内部没有单独放置数组名,而是放置了 &a ,表取出整个数组的地址
	//故 sizeof 计算一个地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*&a));
	//sizeof 内部虽然看似没有单独放置数组名,但是通过 &a 取出整个数组地址
	//然后通过 * 找到整个地址,与 sizeof(a) 没有差别
	//故这里的 sizeof 计算的也是整个数组的大小,即 4(int类型)*4(元素个数)=16
	printf("%d\n", sizeof(&a + 1));
	//sizeof 内部没有单独放置数组名,&a+1 表取出整个数组的地址,并向后跳跃一个数组类型的大小
	//即此时的地址是指向元素 4 的后面一块 int 类型的内存空间
	//故 sizeof 计算地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(&a[0]));
	//sizeof 内部没有单独放置数组名,&a[0] 表取出数组第一个元素的地址
	//故 sizeof 计算地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(&a[0] + 1));
	//sizeof 内部没有单独放置数组名,&a[0]+1 表取出数组第一个元素地址并向后跳跃一个 int 类型的大小
	//故 sizeof 计算的是地址(指针)的大小为 4 or 8
	return 0;
}

2.2字符数组

#include <stdio.h>
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));
	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));
	return 0;
}
#include <stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };//非字符串!!!!!!
	printf("%d\n", sizeof(arr));
	//sizeof 内部单独放置数组名,故计算的是整个数组的大小
	//即大小为 1(char类型)*6(元素个数)=6
	printf("%d\n", sizeof(arr + 0));
	//sizeof 内部没有单独放置数组名,arr 表数组首元素地址,arr+0 亦表示首元素地址
	//故 sizeof 计算地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*arr));
	//sizeof 内部没有单独放置数组名,arr 表数组首元素地址,*arr 表对该地址解引用
	//便得到数组第一个元素 'a' ,故大小为 1(char类型)
	printf("%d\n", sizeof(arr[1]));
	//sizeof 内部没有单独放置数组名,arr[1] 表数组第二个元素,即 'b'
	//故大小为 1(char类型)
	printf("%d\n", sizeof(&arr));
	//sizeof 内部没有单独放置数组名,&arr 表取出整个数组的地址
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(&arr + 1));
	//sizeof 内部没有单独放置数组名,&arr+1 表取出整个数组的地址并向后跳跃一个数组类型的大小
	//即指向元素 'f' 后一个 char 类型的空间
	//故 sizeof 计算的是地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(&arr[0] + 1));
	//sizeof 内部没有单独放置数组名,&arr[0]+1 表取出数组一个元素的地址并向后跳跃一个 char 类型的大小
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", strlen(arr));
	//strlen 不是 sizeof ,故 arr 表数组首元素地址,strlen 会以此地址开始向后寻找 '\0'
	//但此数组并不包含 '\0' ,故 strlen 的返回值为随机值
	printf("%d\n", strlen(arr + 0));
	//strlen 不是 sizeof ,arr+0 表首元素地址,strlen 的返回值也是一个随机值
	printf("%d\n", strlen(*arr));
	//strlen 不是 sizeof ,*arr 表对数组首元素地址解引用,得到字符 'a' ,其 ASCLL 码值为 97
	//strlen 会以 97 为起始地址向后寻找 '\0' 
	//但个人理解认为:97 是一个没有初始化的指针(地址),即野指针
	//故这里会报错
	printf("%d\n", strlen(arr[1]));
	//arr[1] 表数组的第二个元素 'b' ,其 ASCLL 码值为 98
	//strlen 会以 98 为起始地址向后寻找 '\0'
	//但个人理解认位:98 是一个没有初始化的指针(地址),即野指针
	//故这里依然会报错
	printf("%d\n", strlen(&arr));
	//&arr 表取出整个数组的地址,strlen 会以此作为起始地址向后寻找 '\0'
	//这里需要注意,在 strlen 的函数声明当中,参数是一个 char* 类型的指针
	//也就是我们虽然传参时传了一个数组指针,但是 strlen 接收时会自动强转为 char* 类型指针
	//故数组并不包含 '\0' ,strlen 的返回值是一个随机值
	printf("%d\n", strlen(&arr + 1));
	//&arr+1 表取出整个数组的地址并向后跳跃一个数组类型的大小
	//即指向了元素 'f' 的后一块 char 类型的空间
	//strlen 会以此地址作为起始地址向后寻找 '\0'
	//但因我们无法确定 '\0' 的位置,所以 strlen 的返回值是一个随机值
	printf("%d\n", strlen(&arr[0] + 1));
	//&arr[0]+1 表取出数组首元素地址并向后跳跃一个 char 类型的大小
	//即指向了元素 'b' ,strlen 会以此地址作为起始地址向后寻找 '\0'
	//但数组中并不包含 '\0' ,故 strlen 的返回值是一个随机值
	return 0;
}

我们把报错的两条语句注释掉:

2.3字符串数组

#include <stdio.h>
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));
	return 0;
}
#include <stdio.h>
int main()
{
	char arr[] = "abcdef";//注意数组里面放的是字符串!!!
	printf("%d\n", sizeof(arr));
	//sizeof 内部单独放置数组名,即计算整个数组的大小
	//大小为 1(char类型)*7(元素个数)=7
	printf("%d\n", sizeof(arr + 0));
	//sizeof 内部没有单独放置数组名,arr+0 表数组首元素地址
	//故 sizeof 计算地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*arr));
	//sizeof 内部没有单独放置数组名,*arr 表对数组首元素地址解引用
	//即得到字符 'b' ,故大小为 1(char类型)
	printf("%d\n", sizeof(arr[1]));
	//sizeof 内部没有单独放置数组名,arr[1] 表数组第二个元素即字符 'b'
	//故大小为 1(char类型)
	printf("%d\n", sizeof(&arr));
	//sizeof 内部没有单独放置数组名,&arr 表对整个数组取地址
	//故 sizeof 计算的地址(指针)大小为 4 or 8
	printf("%d\n", sizeof(&arr + 1));
	//sizeof 内部没有单独放置数组名,&arr+1 表取出整个数组地址并向后跳跃一个数组类型大小
	//即指向元素 '\0' 后面一块数组类型大小的空间
	//故 sizeof 计算的地址(指针)大小为 4 or 8
	printf("%d\n", sizeof(&arr[0] + 1));
	//sizeof 内部没有单独放置数组名,&arr[0]+1 表取出数组首元素地址并向后跳跃一个 char 类型大小
	//即指向数组第二个元素
	//故 sizeof 计算的地址(指针)大小为 4 or 8
	printf("%d\n", strlen(arr));
	//strlen 不是 sizeof ,arr 表数组首元素地址,strlen 会以此为起始地址向后寻找 '\0'
	//因为此数组包含 '\0' ,故 strlen 的返回值为 6
	printf("%d\n", strlen(arr + 0));
	//arr+0 表数组首元素地址,strlen 会以此地址为起始地址向后寻找 '\0'
	//因为此数组包含 '\0' ,故 strlen 的返回值为 6
	printf("%d\n", strlen(*arr));
	//*arr 表对数组首元素地址解引用,得到字符 'a' ,其 ASCLL 码值为 97
	//故 strlen 会以此地址为起始地址向后寻找 '\0'
	//但个人理解认位: 97 是一个没有初始化的指针(地址),即野指针
	//故这里会报错
	printf("%d\n", strlen(arr[1]));
	//arr[1] 表数组第二个元素,即字符 'b' ,其 ASCLL 码值为 98
	//strlen 会以此地址会起始地址向后寻找 '\0'
	//但个人理解认位:98 是一个没有初始化的指针(地址),即野指针
	//故这里会报错
	printf("%d\n", strlen(&arr));
	//&arr 表取出整个数组的地址,但观察 strlen 函数的声明可以发现
	//strlen 的函数参数是一个 char* 类型的指针
	//即我们传参传进去的是一个数组指针,当 strlen 接收的时候,会将其强转为字符指针
	//故 strlen 会以数组首元素地址为起始地址,向后寻找 '\0'
	//因为数组包含 '\0' ,故 strlen 的返回值为 6
	printf("%d\n", strlen(&arr + 1));
	//&arr+1 表取出整个数组的地址并向后跳跃一个数组类型大小
	//即指向 '\0' 后一块数组类型的空间
	//strlen 会以此地址为起始地址向后寻找 '\0'
	//但我们无法确定 '\0' 的具体位置,所以 strlen 会返回一个随机值
	printf("%d\n", strlen(&arr[0] + 1));
	//&arr[0]+1 表取出数组首元素地址并向后跳跃一个 char 类型的大小
	//即指向了数组第二个元素的地址
	//strlen 会以此地址作为起始地址向后寻找 '\0'
	//故 strlen 的返回值为 5
	return 0;
}

我们把报错的语句注释掉:

2.4字符串指针

#include <stdio.h>
int main()
{
	char* p = "abcdef";//p 变量存放的是字符串常量的首元素地址
	printf("%d\n", sizeof(p));
	//sizeof 计算地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(p + 1));
	//p+1 表字符串常量的第二个元素的地址
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*p));
	//*p 表对字符串常量首元素地址解引用。得到字符 'a'
	//故计算的大小为 1(char类型)
	printf("%d\n", sizeof(p[0]));
	//p[0] 可改写成 *(p+0) ,表对字符串常量首元素地址解引用,得到字符 'a'
	//即计算的大小为 1(char类型)
	printf("%d\n", sizeof(&p));
	//&p 表对 char* 类型指针取地址
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(&p + 1));
	//&p+1 表对 char* 类型指针变量 p 取地址并向后跳跃一个 char 类型的大小
	//指向的空间是未知的
	//但 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(&p[0] + 1));
	//&p[0]+1 可改写成 &(*(p+0))+1 ,表取出字符串常量的首元素地址并向后跳跃一个 char 类型的大小
	//即指向了字符 'b'
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", strlen(p));
	//strlen 不是 sizeof ,p表字符串首元素地址
	//strlen 以此地址为起始地址,向后寻找 '\0'
	//故 strlen 的返回值为 6
	printf("%d\n", strlen(p + 1));
	//p+1 表字符串常量的第二个元素的地址,strlen 会以此为地址向后寻找 '\0'
	//故 strlen 的返回值为 5
	printf("%d\n", strlen(*p));
	//*p 表字符串常量首元素,即字符 'a',strlen 会以此为地址向后寻找 '\0'
	//但个人理解人为:'a' 的 ASCLL 码值为 97 ,但 97 是一个没有被初始化的指针(地址),即野指针
	//故这里会报错
	printf("%d\n", strlen(p[0]));
	//p[0] 可改写成 *(p+0) ,表字符串常量首元素,即字符 'a',其 ASCLL 码值为 97
	//strlen 会以此地址为起始地址向后寻找 '\0'
	//但个人理解认位:97 是一个没有被初始化的指针(地址),即野指针
	//故这里会报错
	printf("%d\n", strlen(&p));
	//&p 表取出 char* 类型指针变量的地址,strlen 以此地址为起始地址向后寻找 '\0'
	//但我们无法确定 '\0' 的位置
	//故 strlen 会返回一个随机值
	printf("%d\n", strlen(&p + 1));
	//&p+1 表取出 char* 类型指针变量的地址并向后跳跃一个 char 类型的大小,strlen 以此地址为起始地址向后寻找 '\0'
	//但我们无法确定 '\0'的位置,故 strlen 的返回值会返回一个随机值
	printf("%d\n", strlen(&p[0] + 1));
	//*p{0}+1 可改写为 &(*(p+0))+1 ,表取出字符串常量首元素地址并向后跳跃一个 char 类型的大小
	//即指向了字符串常量的第二个元素的地址,strlen 会以此地址为起始地址向后寻找 '\0'
	//故 strlen 的返回值为 5
	return 0;
}

我们对报错的两条语句注释:

2.5二维数组

#include <stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	//sizeof 内部放置的是数组名,故计算整个数组的大小
	//即大小为 4(int类型)*12(元素个数)=48
	printf("%d\n", sizeof(a[0][0]));
	//sizeof 内部没有单独放置数组名,a[0][p] 表数组首元素
	//故 sizeof 的计算值为 4(int类型)
	printf("%d\n", sizeof(a[0]));
	//sizeof 内部放置的看似不是单独的数组名,但 a[0] 表数组的第一个元素
	//此元素也是一个数组
	//故 sizeof 计算的大小为 4(int类型)*4(元素个数)=16
	printf("%d\n", sizeof(a[0] + 1));
	//sizeof 内部放置的不是单独的数组名,a[0] 表二维数组的第一个元素,即拿到了一个数组
	//a[0]+1 表二维数组的第一个数组元素的地址并向后跳跃一个 int 类型的大小
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*(a[0] + 1)));
	//*(a[0]+1) 表对二维数组的第一个数组元素的地址并向后跳跃一个 int 类型的大小的解引用
	//即找到了二维数组中的某一个元素
	//故 sizeof 计算的大小为 4(int类型)
	printf("%d\n", sizeof(a + 1));
	//sizeof 内部没有单独放置数组名,a+1 表二维数组的首元素地址并向后跳跃一个一维数组类型的大小
	//即指向了二维数组的第二个数组元素的地址
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*(a + 1)));
	//*(a+1) 表对二维数组的首元素地址并向后跳跃一个一维数组类型的大小的解引用
	//即得到了二维数组的第二个元素
	//此元素为一个一维数组,故 sizeof 计算的大小为 4(int类型)*4(元素个数)=16
	printf("%d\n", sizeof(&a[0] + 1));
	//&a[0]+1 表二维数组的首元素取地址并向后跳跃一个一维数组的类型大小
	//指向了二维数组的第二个元素
	//故 sizeof 计算的地址(指针)的大小为 4 or 8
	printf("%d\n", sizeof(*(&a[0] + 1)));
	//*(&a[0]+1) 表对二维数组的首元素取地址并向后跳跃一个一维数组的类型大小的解引用
	//即得到了二维数组的第二个元素
	//此元素是一个一维数组,故 sizeof 计算的大小的 4(int类型)*4(元素个数)=16
	printf("%d\n", sizeof(*a));
	//sizeof 内部没有单独放置数组名,*a 表对二维数组首元素地址解引用
	//得到一个一维数组
	//故 sizeof 计算的大小为 4(int类型)*4(元素个数)=16
	printf("%d\n", sizeof(a[3]));
	//a[3] 表二维数组的第三个元素
	//需要说明的是,sizeof 只对类型感兴趣
	//也就是说,二维数组虽然不存在第三个元素,但它的类型依旧是二维数组
	//故 sizeof 计算的是 4(int类型)*4(元素个数)=16
	return 0;
}

到此这篇关于C语言例题讲解指针与数组的文章就介绍到这了,更多相关C语言指针与数组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • VC++实现程序开机启动运行的方法

    VC++实现程序开机启动运行的方法

    这篇文章主要介绍了VC++实现程序开机启动运行的方法,很实用的功能,需要的朋友可以参考下
    2014-08-08
  • C++中对C语言结构体用法的扩充

    C++中对C语言结构体用法的扩充

    今天小编就为大家分享一篇关于C++中对C语言结构体用法的扩充,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • c++类构造函数详解

    c++类构造函数详解

    这篇文章主要介绍了c++类构造函数示例,需要的朋友可以参考下
    2014-05-05
  • 详解C++17中类模板参数推导的使用

    详解C++17中类模板参数推导的使用

    自C++17起就通过使用类模板参数推导,只要编译器能根据初始值推导出所有模板参数,那么就可以不指明参数,下面我们就来看看C++17中类模板参数推导的具体使用吧
    2024-03-03
  • Qt编程实现小时钟

    Qt编程实现小时钟

    这篇文章主要为大家详细介绍了Qt编程实现小时钟,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • C语言 如何用堆解决Topk问题

    C语言 如何用堆解决Topk问题

    TopK问题即在N个数中找出最大的前K个,这篇文章将详细讲解如何利用小根堆的方法解决TopK问题,文中代码具有一定参考价值,快跟随小编一起学习一下吧
    2021-12-12
  • c语言单词本的新增、删除、查询按顺序显示功能

    c语言单词本的新增、删除、查询按顺序显示功能

    这篇文章主要介绍了c语言单词本的新增、删除、查询按顺序显示功能,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • C语言示例讲解while循环语句的用法

    C语言示例讲解while循环语句的用法

    在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,C语言while语句可以是单个语句,也可以是一个语句块,其条件可以是任意表达式,true是任意非零值,当条件为真时,循环进行迭代
    2022-06-06
  • C++中的while循环和for循环语句学习教程

    C++中的while循环和for循环语句学习教程

    这篇文章主要介绍了C++中的while循环和for循环语句学习教程,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • Clion-MinGW编译后的exe文件添加ico图标的操作方法

    Clion-MinGW编译后的exe文件添加ico图标的操作方法

    这篇文章主要介绍了Clion-MinGW编译后的exe文件添加ico图标的操作方法,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07

最新评论