【C语言】进阶指针(三)—>指针与数组笔试真题详解(上)

简介: 【C语言】进阶指针(三)—>指针与数组笔试真题详解(上)

前言:

本篇会列出全部有关数组和指针含义的内容、实例及分析,并引入八道笔试真题进行实操练习,干货满满。

贯穿本篇的核心知识就是数组名的意义

1、sizeof(数组名),这里的数组名表示整个数组,sizeof计算的是整个数组的大小,注意括号中必须为数组名才满足这一意义,比如sizeof(arr+1)就不是整个数组的大小了,&数组名同理。

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

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

一、一维数组

int main()
{
  //一维数组
  int a[] = { 1,2,3,4 };
  printf("%d\n", sizeof(a));        //16 
    //a为数组名,sizeof(数组名)计算的是整个数组的大小,即4*4=16  
  printf("%d\n", sizeof(a + 0));    //4/8
    //a为数组名,代表首元素地址,a+0还是首元素地址,只要是地址,大小即为4/8  
  printf("%d\n", sizeof(*a));     //4
    //*a为数组中的元素1,为int类型,sizeof(int)为4
  printf("%d\n", sizeof(a + 1));    //4/8
    //a+1指向数组中的元素2,为int*,只要是指针类型,大小即为4/8
  printf("%d\n", sizeof(a[1]));   //4
  printf("%d\n", sizeof(&a));     //4/8
    //&数组名取出的是整个数组的地址,但是仍为地址,所以大小为4/8
  printf("%d\n", sizeof(*&a));    //16
    //*&a相当于a,sizeof(数组名)计算的是整个数组的大小,为16
  printf("%d\n", sizeof(&a + 1));   //4/8
    //&a+1指向4后面一个元素,但是&a+1是指针,所以大小为4/8
  printf("%d\n", sizeof(&a[0]));    //4/8
    //首元素地址,大小为4/8
  printf("%d\n", sizeof(&a[0] + 1));//4/8
    //&a[0]+1指向元素2,但他也是指针,所以大小为4/8
  return 0;
}

经过对一维数组的分析, 我们可以知道:

1、在判断时,只要是指针,那么他的大小即为4/8,32位为4,64位为8,可以加快我们做题判断的速度。

2、指针的步长取决于指针的类型,指针的类型为int,那么指针加+1就是跳过一个int类型,指针类型为数组,那么指针+1就是跳过整个数组。

二、字符数组

字符数组的分析除了sizeof我们再引入strlen库函数进行更深入的分析。

strlen函数的参数为const char*,功能为统计'\0'前的元素个数。

int main()
{
  //字符数组
  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
  printf("%d\n", strlen(arr));        //随机
    //该字符数组不是字符串,'\0'的位置不确定,所以为随机值
  printf("%d\n", strlen(arr + 0));    //随机
  printf("%d\n", strlen(*arr));       //err
    //strlen需要的参数是指针,而*arr是字符'a'。ASCII值为97
    //字符'a'的ASCII值为97,strlen会从97这个地址开始计算字符串长度
    //会造成非法访问
  printf("%d\n", strlen(arr[1]));     //err
  printf("%d\n", strlen(&arr));       //随机
  printf("%d\n", strlen(&arr + 1));   //随机
  printf("%d\n", strlen(&arr[0] + 1));//随机
  char arr[] = "abcdef";
  printf("%d\n", sizeof(arr));        //7
  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
  printf("%d\n", strlen(arr));        //6
  printf("%d\n", strlen(arr + 0));    //6
  printf("%d\n", strlen(*arr));       //err
  printf("%d\n", strlen(arr[1]));     //err
  printf("%d\n", strlen(&arr));       //6
  printf("%d\n", strlen(&arr + 1));   //随机
    //该指针步长为该字符串,+1后指针指向'\0'的后一个位置,所以值为随机
  printf("%d\n", strlen(&arr[0] + 1));//5
    //该指针步长为一个字符,+1后指针指向字符'b',所以计算值为5
  char* p = "abcdef";
    //经过前面的学习我们知道p存放的是该字符串首个字符的地址
  printf("%d\n", sizeof(p));          //4/8
  printf("%d\n", sizeof(p + 1));      //4/8
  printf("%d\n", sizeof(*p));         //1
  printf("%d\n", sizeof(p[0]));       //1
  printf("%d\n", sizeof(&p));         //4/8
  printf("%d\n", sizeof(&p + 1));     //4/8
    //思考:这里指针指向了哪里??
  printf("%d\n", sizeof(&p[0] + 1));  //4/8
  printf("%d\n", strlen(p));          //6
  printf("%d\n", strlen(p + 1));      //5
  printf("%d\n", strlen(*p));         //err
  printf("%d\n", strlen(p[0]));       //err
  printf("%d\n", strlen(&p));         //随机
  printf("%d\n", strlen(&p + 1));     //随机
  printf("%d\n", strlen(&p[0] + 1));  //5
  return 0;
}

char* p="hello world";

字符指针p存放的是该字符串首个字符的地址。

我想单独讲解一下这段代码:

int main
{
    char* p = "abcdef";
    printf("%d\n", sizeof(&p));         //4/8
    printf("%d\n", sizeof(&p + 1));     //4/8
    //思考:这里指针指向了哪里??
    return 0;
}

首先我们知道p指向的是字符'a',即p的类型为char*,在&p后,&p的类型就是char**,此时给&p+1,&p的步长应为char*,也就是指针&p+1相对于&p跳过了一个char* ,比如p的地址是0x0012ff40,如图:

也就是&p是指针的指针,所以他的步长应为一个指针的长度

其中相似原理的我并未重复注释,大家有问题的可以评论或者私信问我🌹🌹🌹

三、二维数组

首先我们需要知道:

假定一个二维数组int a[3][4],对于二维数组a来说,a[0]就是该二维数组第一行的一维数组的数组名,同理a[1]就是该二维数组第二行的一维数组的数组名,又因为数组名就是数组首元素的地址,所以a[0]就是该二维数组第一行的一维数组的首元素地址,同理a[1]就是该二维数组第二行的一维数组的首元素地址。

在了解了上面的概念后,接下来的代码就迎刃而解了。

int main()
{
  //二维数组
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));           //48
  printf("%d\n", sizeof(a[0][0]));     //4
  printf("%d\n", sizeof(a[0]));        //16
  printf("%d\n", sizeof(a[0] + 1));    //4/8
    //即a[0]其实就是a[0][0]的地址,+1后变为a[0][1]的地址,只要是地址,大小就是4/8
  printf("%d\n", sizeof(*(a[0] + 1))); //4
  printf("%d\n", sizeof(a + 1));       //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
    //a[0]是第一行数组的数组名,所以&a[0]取出的是该一维数组的地址
    //+1后指向了第二行的一维数组,解引用后是第二行一维数组,大小为4*4=16
  printf("%d\n", sizeof(*a));          //16
  printf("%d\n", sizeof(a[3]));        //16
    //越界会影响sizeof的计算么??
  return 0;
}

sizeof是如何计算的?

我们发现最后一个题目中数组越界了,但并没有影响程序的运行,也就是说,sizeof的计算只考虑类型,不会真的访问计算,a[3]的类型是int [4],所以大小为4*4=16。

四、指针笔试题

笔试题(1)

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf( "%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}
//程序的结果是什么?

答案:2,5

分析:

a代表首元素地址,指针类型为int*,步长为int,+1后指向元素'2',解引用后为元素'2',所以打印值为2。

&a拿到的是整个数组的地址,指针类型为int(*)[5],步长为int [5],+1后ptr指向元素'5'后面的位置,并将指针强制转换为int*类型,ptr指针类型为int*,步长为int,-1后ptr指向元素'5',解引用得到元素'5',所以打印值为5。


目录
相关文章
|
24天前
|
存储 C语言
【C语言基础】一篇文章搞懂指针的基本使用
本文介绍了指针的概念及其在编程中的应用。指针本质上是内存地址,通过指针变量存储并间接访问内存中的值。定义指针变量的基本格式为 `基类型 *指针变量名`。取地址操作符`&`用于获取变量地址,取值操作符`*`用于获取地址对应的数据。指针的应用场景包括传递变量地址以实现在函数间修改值,以及通过对指针进行偏移来访问数组元素等。此外,还介绍了如何使用`malloc`动态申请堆内存,并需手动释放。
|
24天前
|
存储 编译器 C语言
【C语言基础考研向】09 一维数组
数组是一种有序集合,用于存储相同类型的数据,便于统一操作与管理。例如,将衣柜底层划分为10个格子存放鞋子,便于快速定位。在C语言中,数组定义格式为 `类型说明符数组名[常量表达式];`,如 `int a[10];` 表示定义了一个包含10个整数的数组。数组初始化时可以直接赋值,也可以部分赋值,且数组长度必须固定。数组在内存中连续存储,访问时需注意下标范围,避免越界导致数据异常。数组作为参数传递时,传递的是首地址,修改会影响原数组。
|
24天前
|
存储 C语言
【C语言基础考研向】10 字符数组初始化及传递和scanf 读取字符串
本文介绍了C语言中字符数组的初始化方法及其在函数间传递的注意事项。字符数组初始化有两种方式:逐个字符赋值或整体初始化字符串。实际工作中常用后者,如`char c[10]="hello"`。示例代码展示了如何初始化及传递字符数组,并解释了为何未正确添加结束符`\0`会导致乱码。此外,还讨论了`scanf`函数读取字符串时忽略空格和回车的特点。
|
27天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
27天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第六章 数组_一维数组_二维数组_字符数组详解
本章介绍了C语言中的数组概念及应用。数组是一种存储同一类型数据的线性结构,通过下标访问元素。一维数组定义需指定长度,如`int a[10]`,并遵循命名规则。数组元素初始化可使用 `{}`,多余初值补0,少则随机。二维数组扩展了维度,定义形式为`int a[3][4]`,按行优先顺序存储。字符数组用于存储字符串,初始化时需添加结束符`\0`。此外,介绍了字符串处理函数,如`strcat()`、`strcpy()`、`strcmp()` 和 `strlen()`,用于拼接、复制、比较和计算字符串长度。
|
1月前
|
存储 安全 C语言
C语言 二级指针应用场景
本文介绍了二级指针在 C 语言中的应用,
|
2月前
|
搜索推荐 C语言
指针与数组
指针与数组
51 9
|
2月前
|
存储 编译器 数据处理
【编程秘籍】解锁C语言数组的奥秘:从零开始,深入浅出,带你领略数组的魅力与实战技巧!
【8月更文挑战第22天】数组是C语言中存储同类型元素的基本结构。本文从定义出发,详述数组声明、初始化与访问。示例展示如何声明如`int numbers[5];`的数组,并通过下标访问元素。初始化可在声明时进行,如`int numbers[] = {1,2,3,4,5};`,编译器自动计算大小。初始化时未指定的元素默认为0。通过循环可遍历数组,数组名视为指向首元素的指针,方便传递给函数。多维数组表示矩阵,如`int matrix[3][4];`。动态数组利用`malloc()`分配内存,需用`free()`释放以避免内存泄漏。掌握这些技巧是高效数据处理的基础。
56 2
|
2月前
|
存储 编译器 C语言
【C语言篇】深入理解指针2
代码 const char* pstr = "hello world."; 特别容易让初学者以为是把字符串 hello world.放 到字符指针 pstr ⾥了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。
|
2月前
|
存储 程序员 编译器
【C语言篇】深入理解指针1
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。