c语言学习第二十一课-指针和数组笔试题解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: c语言学习第二十一课-指针和数组笔试题解析

要想熟练的面对数组与指针方面的笔试题。首先我们先大致了解一下,关于数组与指针。

一,数组

数组的构成是 数据类型+数组名[常量表达式],数组无法直接引用其全部,只能逐一的引用数组元素,数组的表达形式是数组名[下标]。

对于数组用来传参,数组名一般代表数组首元素地址。

二,指针

首先指针就是地址,定义形式为  指针类型+变量名称,这个变量里的数值被认定为内存里的地址。对于指针,我们要详细的了解其指针的类型,指针指向的类型。

int *a;//指针的类型是int *型,指针指向的类型是int型
int **a;//指针的类型是int **型,指针指向的类型是int *型
int(*a)[3];//指针的类型是int (*)[]型,指针指向的类型是 int()[]型

数组与指针

指针->地址,指针变量->大小4/8字节

数组,大部分情况数组名就是数组首元素地址  但有两个例外

sizeof(数组名)  

&数组名-数组名表示整个数组-取出的是数组地址

这两个数组名代表的是整个数组的地址

一般的,指针与数组可以相对的表示 *a->&a[o]->a[0]

这里的考察主要通过 操作符sizeof与函数strlen两个对数组与指针的考察,但在此前,先了解一下

操作符sizeof()

sizeof()作为一个单目运算符,是用来计算对应操作数的所占空间大小,它里面的参数可以是,数组,指针,函数,类型等。不管是是什么,都是计算对应数所占空间大小,单位是字节。

对于sizeof(),sizeof表达式不会真的去访问它,只看类型.

  /*
    * int a=5;
    * short s=11;
    * printf("%d\n",sizeof(s=a+2));//2  short类型,sizeof只看类型,不计算
    * printf("%d\n",s);// 实际为7    但不计算,还是11
    * return 0
    * 
    * 对于表达式a+3有两种类型:
    * 值属性
    * 类型属性      //sizeof()只关注类型属性,不关注值属性
    */

函数strlen()

strlen()函数是用来求字符串长度

strlen只针对字符串,求的是字符串的长度。本质上是“\0”前的字符长度,其参数是指针才可以,否则会造成非法访问,若无“\0”,则长度为随机值

例题展示

现在我们来深入sizeof与strlen,举例一个整型数组,此时用sizeof 计算

     int a[] = { 1,2,3,4 };
  printf("%d\n", sizeof(a));//16
  //szieof)(a)就是数组名单独放在sizeof内部,计算数组总大小,单位是字节
  printf("%d\n", sizeof(a + 0));//4/8个字节
  //a+0其实是数组首元素地址
  printf("%d\n", sizeof(*a));//4
  //数组首元素
  //*a->&a[o]->a[0]
  printf("%d\n", sizeof(a + 1));//4/8个字节
  //a是数组首元素,a+1是第二个元素的地址
  printf("%d\n", sizeof(a[1]));//4
  printf("%d\n", sizeof(&a));//4或者8
  //&a-取出的是整个数组的地址。是一个地址
  //int (*pa)[4]=&a;int (*)[4]
  printf("%d\n", sizeof(*&a));//16
  //sizeof(a);
  //int (*)a;
  printf("%d\n", sizeof(&a + 1));//4/8
  //&a+1跳过一个数组,在该数组地址末尾
  printf("%d\n", sizeof(&a[0]));//4/8
  printf("%d\n", sizeof(&a[0] + 1));//4/8
  //第二个元素的地址

在上面中,若a单独放进sizeof中,就是正常作用,此时a代表整个数组,计算总空间大小为4*4个字节,若没有单独放,如a+0;那么a代表首元素地址,加零还是首元素地址,地址的大小为4或8个字节。其次sizeof(&a)这里取出的地址是整个数组的地址,int (*pa)[4]=&a,数组与指针的相互表示。若&a+1则表示跳过这个数组这一块空间,

a7c1ed8bf5c140f6845d5d3377e50d48.png

之后我们再以arr的字符型数组为例,用sizeof()来计算一次

    char arr[] = { 'a','b','c','d','e','f'};
    printf("%d\n", sizeof(arr));//6
  printf("%d\n", sizeof(arr + 0));//4/8
  //数组首元素的地址
  printf("%d\n", sizeof(*arr));//1
  //表示首元素地址,单独放进来的*,是首元素。
  printf("%d\n", sizeof(arr[1]));//1
  printf("%d\n", sizeof(&arr));//4/8
  //取出的是全部地址,但也是一个地址
  printf("%d\n", sizeof(&arr + 1));//4/8
  //末尾地址
  printf("%d\n", sizeof(&arr[0] + 1));//4/8
  //第二个元素地址

上面的数组类型不一样,计算的空间大小不一样,但本质都是看对于 arr   arr +0  *arr  *arr+ 1    &arr   &arr+1   a[0]   等的本质理解它是代表什么。

我们在举例关于strlen的计算,

char arr[] = { 'a','b','c','d','e','f' };
  printf("%d\n", strlen(arr));//随机值
  //arr数组名,首元素地址,但不知道什么时候遇到‘\0’
  printf("%d\n", strlen(arr + 0));//随机值
  //+0还是首元素地址
  printf("%d\n", strlen(*arr));//非法访问
  //放的不是地址,*arr=a[0]是‘a'
  printf("%d\n", strlen(arr[1]));//无非访问
  //与上同理
  printf("%d\n", strlen(&arr));//随机值
  //无法确定“\0”的位置
  printf("%d\n", strlen(&arr + 1));//随机值-6
  //末尾地址,找不到’\0‘
  printf("%d\n", strlen(&arr[0] + 1));//随机值-1
  //第二个地址往后,找不到’\0‘

以上字符数组例子都是在数组中无法找到“\0”的,所以在计算时会出现随机值。

若改变数组再利用sizeof 与strlen 各计算一遍

char arr[] = "abcdef";//[a,b.c.d.e.f,\0]
  printf("%d\n", sizeof(arr));//7
  //计算数组大小,7个字节
  printf("%d\n", sizeof(arr + 0));//4/8
  printf("%d\n", sizeof(*arr));// 1
  //数组首元素。*arr= (*arr+0)= arr[0] 
  printf("%d\n", sizeof(arr[1]));//1
  printf("%d\n", sizeof(&arr));//4/8
  printf("%d\n", sizeof(&arr + 1));//4/8
  printf("%d\n", sizeof(&arr[0] + 1));//4/8
  printf("%d\n", strlen(arr));//6
  printf("%d\n", strlen(arr+0));//6
    //从首元素开始计算
  printf("%d\n", strlen(*arr));//无法访问
  printf("%d\n", strlen(&arr));//6
  //取出的类型不一样,但不影响
  printf("%d\n", strlen(&arr+1));//随机值
    //在末尾地址
  printf("%d\n", strlen(arr[0]+1));//5

对于arr在取地址操作时,他取出的是整个数组的地址。

此外对于一个变量指针存放数组再计算.,比较sizeof与strlen的区别。

int main()
{
  char* p = "abcdef";
  printf("%d\0", sizeof(p));//4/8
  //指针的大小
  printf("%d\0", sizeof(p + 1));//4/8
  //指向第二个元素的地址
  printf("%d\0", sizeof(*p));//1
  //表示首字符
  printf("%d\0", sizeof(p[0]));//==*(p+0)  为1
    //可以理解为一个数组
  printf("%d\0", sizeof(&p));//4/8
  //取出的是地址,开辟p时的地址,与abcdef无关
  printf("%d\0", sizeof(&p + 1));//4/8
  //跳过一个p
  //char *p;char* *p=&p;
  printf("%d\0", sizeof(&p[0]+1));//4/8
  //b的地址
  printf("%d\n", strlen(p));//6
  printf("%d\n", strlen(p+1));//5
  //跳过一个地址
  printf("%d\n", strlen(*p));//非法访问
  printf("%d\n", strlen(p[0]));//非法访问
  printf("%d\n", strlen(&p));//随机值
  //在地址里找'\0’
  //不知哪里有”\0“
  printf("%d\n", strlen(&p + 1));//随机值
  printf("%d\n", strlen(p[0] + 1));//5
}

这里用指针表示数组,效果一样,我们可以直接理解为数组放进去。除了数组名单独放,它都是一个表示首元素地址的效果(&p,代表取出整个地址),才是也是无法找到“\0”。

这里我们再用二维数组举例,再看sizeof与strlen在这里的情况。

int main()//二维数组数组名没单独放。则是第一行地址
{
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));//a的数组名单独放在sizeof里 代表所有大小  48
  printf("%d\n", sizeof(a[0][0]));//第一行第一个元素   4
  printf("%d\n", sizeof(a[0]));//16 第一行的数组名,数组名单独放在sizeof内部。
  printf("%d\n", sizeof(a[0]+1));//4 不是单独放在sizeof里    a[0]代表首元素地址  是第一行第二个元素地址
  printf("%d\n", sizeof(*(a[0]+1)));// a[0][1]大小 4个字节
  printf("%d\n", sizeof(a+1));//a代表第一行的地址类型  加一为 第二行的地址 4/8
  printf("%d\n", sizeof( * (a + 1)));//16
  //第二行的大小  
  printf("%d\n", sizeof(&a[0]+1));//取出第一行的地址 加一  第二行的地址 4/8
  printf("%d\n", sizeof(*(&a[0] + 1)));  //第二行的元素大小  16
  printf("%d\n", sizeof(*a));//表示第一行的大小  16
  printf("%d\n", sizeof(a[3]));//第四行元素  16  四个0  
}

对于二维数组,sizeof(a)

我们知道二维数组是连续储存的,那么它的结构应该是这样。


275f1c040c194dbcab6bf80af2171f16.png

,这里的a[0]单独放表示第一行整个的所有元素,a不单独放代表的是第一行的整个地址。

且在最后一个例子当中我们发现sizeof并没有说越界访问,这是因为sizeof只看数据类型,不看值类型,在sizeof中参数表达式不会被计算。

对于sizeof(*arr+1) ,a若单独放*a=arr[0],是代表第一行的元素。 不是单独放,则为首元素地址所以这里是第二个元素。

看完以上这个,举个笔试题。

int main()
{
  int a[5] = { 1,2,3,4,5 };
  int* ptr = (int*)(&a + 1);
  printf("%d %d", *(a + 1), *(ptr - 1));//2 5
  //a是首元素地址在&a+1中。a是全部地址在ptr中
  return 0;
}

这里我们可以看到&a是去除的是整个该数组的地址,且a表示首元素地址。

以上便是今天学习的内容了。

大家一起加油o

相关文章
|
25天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
45 0
|
24天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
25天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
25天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
1月前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
30天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
24天前
|
编译器 C语言
【c语言】指针就该这么学(2)
本文详细介绍了指针与数组的关系,包括指针访问数组、一维数组传参、二级指针、指针数组和数组指针等内容。通过具体代码示例,解释了数组名作为首元素地址的用法,以及如何使用指针数组模拟二维数组和传递二维数组。文章还强调了数组指针与指针数组的区别,并通过调试窗口展示了不同类型指针的差异。最后,总结了指针在数组操作中的重要性和应用场景。
17 0
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
67 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
52 0

推荐镜像

更多