指针和数组笔试题深度解析(上)一

简介: 指针和数组笔试题深度解析(上)

前言


本文带大家详细了解 sizeof 与 strlen 在指针和数组方面的应用,让大家不再傻傻分不清楚,提高大家对其的理解。(注:以下代码均在x86 (32位) 环境下运行)


核心要点


数组名的意义:


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

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

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


sizeof 与 strlen 的作用:


sizeof 是计算对象或者类型创建的对象所占内存空间的大小,单位是字节

sizeof 是操作符,不是函数, sizeof 不关注 \0

strlen 求字符串长度的,从给定的地址出发计算字符串中 \0 之前出现的字符的个数,统计到 \0 为止,如果没有看到 \0,会继续往后找

strlen 是库函数,使用需要包含头文件


指针加一跳多长?


char *p;        //一级指针   *p里的*说明p是指针,指向的类型是char型
char* *pp=&p;   //二级指针   *pp里的*说明pp是指针,指向的类型是char*型


p+1跳过的是一个char型对象

pp+1跳过的是一个char*型对象


指针加一跳多长,取决于指针指向对象的类型


一维数组


下面一段代码大家可以先试着做一做,想一想


#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;
}


输出:


101c57f0c35f453d8963a937b2d2ef31.png


下面我们来逐个分析:


int a[] = {1,2,3,4};       //数组a有4个元素,每个元素占4个字节,
  printf("%d\n",sizeof(a));      // 16
    //a作为数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
  printf("%d\n",sizeof(a+0));   // 4/8
  //a并非单独放在sizeof内部,也没有&,所以数组名a就是数组首元素的地址
  //a+0还是数组首元素的地址,是地址其大小就是 4/8 个字节(x86是4字节,x64是8字节)
  printf("%d\n",sizeof(*a));    // 4
  //a是首元素的地址,*a就是首元素,sizeof(*a)算的就是首元素的大小 
  printf("%d\n",sizeof(a+1));   // 4/8
  //a是首元素的地址,a+1是第二个元素的地址,sizeof(a+1)计算的是指针也就是地址大小
  printf("%d\n",sizeof(a[1]));  // 4
  //a[1]就是数组的第二个元素,sizeof(a[1])的大小 - 4个字节
  printf("%d\n",sizeof(&a));   // 4/8
  //&a取出的整个数组的地址,数组的地址,也是地址呀,sizeof(&a)就是 4/8 个字节
  printf("%d\n",sizeof(*&a));  // 16
  //&a是数组的地址,是数组指针类型,*&a是数组指针解引用,访问一个数组的大小
  //sizeof(*&a) ==> sizeof(a)  =16
  printf("%d\n",sizeof(&a+1));  // 4/8
  //&a数组的地址,&a+1跳过整个数组,&a+1还是地址,是 4/8 个字节
  printf("%d\n",sizeof(&a[0]));  // 4/8
  //a[0]是数组的第一个元素,&a[0]是第一个元素的地址,是 4/8 个字节
  printf("%d\n",sizeof(&a[0]+1));  // 4/8
  //&a[0]是第一个元素的地址,&a[0]+1就是第二个元素的地址,是 4/8 个字节


字符数组


类型一


有了以上讲解相信大家对下面代码应该会得心应手


#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));
  return 0;
}


输出:

928daa8738074d03b574333989189f49.png

分析:


char arr[] = { 'a','b','c','d','e','f' };  //每个 char 型字符占一个字节,整个数组占6个字节
  printf("%d\n", sizeof(arr));      // 6
  //arr是数组名,并且是单独放在sizeof内部,计算的是数组总大小,单位是字节 - 6
  printf("%d\n", sizeof(arr + 0));  // 4/8
  //arr是数组名,并非单独放在sizeof内部,arr表示首元素的地址,arr+0还是首元素的地址
  printf("%d\n", sizeof(*arr));     // 1
  //arr是首元素的地址,*arr就是首元素,sizeof计算的是首元素的大小,是1字节
  printf("%d\n", sizeof(arr[1]));   // 1
  printf("%d\n", sizeof(&arr));     // 4/8   
  //&arr-取出的是数组的地址,sizeof(&arr)计算的是数组的地址的大小,是地址就是4/8字节
  printf("%d\n", sizeof(&arr + 1));  // 4/8
  //&arr是数组的地址,&arr+1跳过整个数组,指向'f'的后边,&arr+1的本质还是地址
  printf("%d\n", sizeof(&arr[0] + 1)); // 4/8
  //&arr[0]是‘a’的地址,&arr[0]+1是'b'的地址,是地址就是4/8字节


我们再来看看 strlen 函数的使用:


#include<stdio.h>
#include<string.h>
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));
  return 0;
}


输出:


18c009d843ad44e3aa20423568c4f0d4.png


为什么会出现这种情况呢?strlen(*arr) 有什么问题呢?


arr是数组首元素的地址,*arr 是首元素 - ‘a’ - 97

strlen就把 ‘a’ 的ASCII码值 97 当成了地址

导致非法访问内存,也就是 err(注:像这种地址都是不能访问的)


它下面的一段代码是 arr[1] ,也就是 ‘b’ - 98,也是不能访问的。

我们将它俩屏蔽再来看看结果:


aeb798904236474d905028c183e3c3aa.png


不知道大家有没有发现好像两次输出的结果有点小差异,第一次输出是:23 23,这与19 19不同,为什么呢?

我们来分析一下:


char arr[] = { 'a','b','c','d','e','f' };
  printf("%d\n", strlen(arr));    //随机值
  //arr是数组名,但是没有放在sizeof内部,也没&,arr就是首元素的地址
  //strlen得到arr后,从arr数组首元素的地方开始计算字符串的长度,直到直到\0,但是arr数组中没有\0,arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
  printf("%d\n", strlen(arr + 0));  //随机值
  //arr是数组首元素的地址,arr+0还是首元素的地址
   //printf("%d\n", strlen(*arr));
   //printf("%d\n", strlen(arr[1]));
  printf("%d\n", strlen(&arr));  //随机值
  //&arr是数组的地址,数组的地址也是指向数组起始位置,和第一个案例一样
  printf("%d\n", strlen(&arr + 1));   //随机值-6
  //跳过整个数组,整个数组大小为6个字节,所以在随机值的基础上-6
  printf("%d\n", strlen(&arr[0] + 1));  //随机值-1
  //&arr[0] + 1是第二个元素地址,所以是随机值-1

相关文章
|
11月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
126 3
|
7月前
|
存储 监控 算法
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
92 7
|
10月前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
258 1
|
11月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
11月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
11月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
11月前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
11月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
201 4
|
11月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
119 2
|
11月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
106 1

热门文章

最新文章

推荐镜像

更多
  • DNS