【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。


目录
相关文章
|
5天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
1天前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
17 5
|
4天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
4天前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
4天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
5天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
5天前
|
C语言
C语言指针(3)
C语言指针(3)
9 1
|
5天前
|
C语言
C语言指针(2)
C语言指针(2)
9 1
|
8天前
|
存储 C语言
C语言:一维数组的不初始化、部分初始化、完全初始化的不同点
C语言中一维数组的初始化有三种情况:不初始化时,数组元素的值是随机的;部分初始化时,未指定的元素会被自动赋值为0;完全初始化时,所有元素都被赋予了初始值。
|
10天前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
13 1