指针和数组笔试题解析(1)

简介: 指针和数组笔试题解析(1)

一、一维数组

下面代码的输出结果是什么:(32位平台下)

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

2020062310470442.png

解析:

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没有单独放在sizeof内部,也没有&,所以代表首元素即a[0]的地址,地址的大小是4/8个字节
printf("%d\n",sizeof(*a));   //4
//a没有单独放在sizeof内部,也没有&,所以代表首元素即a[0]的地址,首元素的地址解引用得到首元素,int 4个字节
printf("%d\n",sizeof(a+1));   //4/8
//a没有单独放在sizeof内部,也没有&,所以代表首元素即a[0]的地址,a+1代表第二个元素的地址,4/8个字节
printf("%d\n",sizeof(a[1]));  //4
//a[1]代表数组第二个元素,整形占4个字节
printf("%d\n",sizeof(&a));  //4/8
//&a取出的是整个数组的地址,地址占4/8个字节
printf("%d\n",sizeof(*&a)); //16
//&a取出整个数组的地址,然后再对其进行解引用,得到整个数组
printf("%d\n",sizeof(&a+1));  //4/8
//&a取出整个数组的地址,&a+1跳过一个数组(跳过一个数组指针)的大小,指向数组末尾,地址大小是4/8个字节
printf("%d\n",sizeof(&a[0])); //4/8
//&a[0]取出的是第一个元素的地址,地址大小为4/8个字节
printf("%d\n",sizeof(&a[0]+1)); //4/8
//&a[0]取出的是第一个元素的地址,&a[0]+1表示第二个元素的地址,地址大小为4/8个字节

总结:

1、数组名的意义

  • 数组名单独放在sizeof内部时表示整个数组;
  • &数组名取出的是整个数组的地址;
  • 其余情况数组名均表示首元素的地址;

2、指针类型的意义

  • 指针的类型决定了指针加减整数时跳过字节/元素的个数;
  • 指针的类型决定了指针解引用时的权限,即访问字节的个数(步长);

二、字符数组

1、题型一

下面代码的输出结果是什么:(32位平台下)

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

2020062310470442.png

20200623104134875.png

解析:

char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));  //6
//arr单独放在sizeof内部,代表整个数组,大小为6个字节
printf("%d\n", sizeof(arr + 0));  //4/8
//arr代表首元素的地址,4/8个字节
printf("%d\n", sizeof(*arr)); //1
//arr代表首元素地址,对其解引用代表第一个元素,大小为1个字节
printf("%d\n", sizeof(arr[1]));    //1
//arr[1]代表数组第二个元素,1个字节
printf("%d\n", sizeof(&arr)); //4/8
//&arr取出整个数组地址,4/8个字节
printf("%d\n", sizeof(&arr + 1)); //4/8
//&arr取出整个数组的地址,&arr+1跳过一个数组,指向数组后面紧挨的空间,4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));  ///4/8
//&arr[0]代表首元素地址,+1代表第二个元素地址,4/8个字节
printf("%d\n", strlen(arr));  //随机值
//arr代表首元素地址,数组从第一个元素开始求字符串长度
//strlen求的是\0以前字符的个数,因为字符数组中并不包含\0,所以strlen会一直往后寻找,直到遇到\0,而我们不知道数组后面空间的内容,所以为随机值。
printf("%d\n", strlen(arr + 0));  //随机值 
//arr+0代表首元素地址,数组从第一个元素开始求字符串长度
//随机值原因同上
printf("%d\n", strlen(*arr)); //error
//strlen函数的参数是一个地址,这里我们把第一个元素即'a'传给strlen函数,那么strlen就会把'a'的ASCII码值(97)当成地址来用,但是97处的地址并不属于我们,从而造成野指针问题,报错
printf("%d\n", strlen(arr[1])); //error
//原因和上面类似
printf("%d\n", strlen(&arr)); //随机值
//&arr虽然取出整个数组的地址,但仍然是指向首元素,所以和上面的strlen(arr)一样
printf("%d\n", strlen(&arr + 1)); //随机值
//&arr取出整个数组的地址,+1跳过整个数组,指向数组后面紧挨的空间,但我们不知道后面空间何时遇到\0,所以仍然是随机值
printf("%d\n", strlen(&arr[0] + 1));  //随机值
//&arr[0]+1代表第二个元素地址,仍然是随机值

2、题型二

下面代码的输出结果是什么:(32位平台下)

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

2020062310470442.png

20200623104134875.png

解析:

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));  //7
//arr代表整个数组,因为字符串末尾会自动补一个\0,所以arr数组有七个元素
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
//strlen遇到字符串末尾的\0停止,前面一共6个元素
printf("%d\n", strlen(arr + 0));  //6
printf("%d\n", strlen(*arr)); //error
printf("%d\n", strlen(arr[1]));    //error
printf("%d\n", strlen(&arr)); //6
printf("%d\n", strlen(&arr + 1)); //随机值
//&arr取出整个数组的地址,+1跳过整个数组,后面空间的内容未知,所以随机
printf("%d\n", strlen(&arr[0] + 1));  //5
//&arr[0]+1是第二个元素的地址,把它传给strlen,所以为5

3、题型三

下面代码的输出结果是什么:(32位平台下)

int main()
{
  char* p = "abcdef";
  printf("%d\n", sizeof(p));
  printf("%d\n", sizeof(p + 1));
  printf("%d\n", sizeof(*p));
  printf("%d\n", sizeof(p[0]));
  printf("%d\n", sizeof(&p));
  printf("%d\n", sizeof(&p + 1));
  printf("%d\n", sizeof(&p[0] + 1));
  printf("%d\n", strlen(p));
  printf("%d\n", strlen(p + 1));
  printf("%d\n", strlen(*p));
  printf("%d\n", strlen(p[0]));
  printf("%d\n", strlen(&p));
  printf("%d\n", strlen(&p + 1));
  printf("%d\n", strlen(&p[0] + 1));
  return 0;
}

2020062310470442.png

20200623104134875.png

解析:

char* p = "abcdef";
printf("%d\n", sizeof(p));  //4/8
//"abcdef"是常量字符串,char* p = "abcdef" 的作用是把字符串中'a'的地址赋给P,所以4/8
printf("%d\n", sizeof(p + 1));  //4/8
//p+1代表字符'b'的地址,4/8
printf("%d\n", sizeof(*p));    //1
printf("%d\n", sizeof(p[0])); //1
printf("%d\n", sizeof(&p));    //4/8
//&p取出的是p的地址,是一个二级指针,但地址大小仍然是4/8
printf("%d\n", sizeof(&p + 1));    //4/8
//&p+1代表p所在空间后面紧挨的空间
printf("%d\n", sizeof(&p[0] + 1));    //4/8
//&p[0] <==> &(*(p+0)) <==> p,代表'a'的地址
printf("%d\n", strlen(p));    //6
printf("%d\n", strlen(p + 1));    //5
printf("%d\n", strlen(*p));    //error
printf("%d\n", strlen(p[0]));    //error
printf("%d\n", strlen(&p));    //随机值
//&p取出的是p的地址,这里有两个东西是不确定的:
//1、不知道p的地址中是否含有四个字节大小的数字0,p的地址可能0x14ffff44,也可能是0x1400ff00
//2、不知道p的后面空间的内容
//所以strlen求出来的值是随机的
printf("%d\n", strlen(&p + 1));    //随机值
//&p+1跳过了p的地址,直接来到了p其后的空间,消除了上面的第一点不确定,但第二段仍然存在
printf("%d\n", strlen(&p[0] + 1));    //5

总结:

1、数组名的意义

  • 数组名单独放在sizeof内部时表示整个数组;
  • &数组名取出的是整个数组的地址;
  • 其余情况数组名均表示首元素的地址;

2、指针类型的意义

  • 指针的类型决定了指针加减整数时跳过字节/元素的个数;
  • 指针的类型决定了指针解引用时的权限,即访问字节的个数(步长);

3、strlen的用法

  • strlen会一直向后寻找,直到遇到 ‘\0’ 才停止计算(越界计数得到随机值);
  • strlen会把传递过来的数据当成地址来使用(错误传递参数导致野指针问题);

三、二维数组

下面代码的输出结果是什么:(32位平台下)

int main()
{
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));
  printf("%d\n", sizeof(a[0][0]));
  printf("%d\n", sizeof(a[0]));
  printf("%d\n", sizeof(a[0] + 1));
  printf("%d\n", sizeof(*(a[0] + 1)));
  printf("%d\n", sizeof(a + 1));
  printf("%d\n", sizeof(*(a + 1)));
  printf("%d\n", sizeof(&a[0] + 1));
  printf("%d\n", sizeof(*(&a[0] + 1)));
  printf("%d\n", sizeof(*a));
  printf("%d\n", sizeof(a[3]));
  return 0;
}

2020062310470442.png

解析:

int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));  //48
  //a单独放在sizeof内部,表示整个二维数组的大小,3*4*4=48
  printf("%d\n", sizeof(a[0][0]));  //4
  //a[0][0]代表第一个元素,整形占4个字节
  printf("%d\n", sizeof(a[0])); //16
  //二维数组的行名代表其对应一维数组的数组名
  //这里的a[0]代表二维数组第一行的数组名
  //一维数组的数组名单独放在sizeof内部,代表整个一维数组,4*4=16
  printf("%d\n", sizeof(a[0] + 1)); //4/8
  //a[0]代表第一行的数组名
  //a[0]不是单独放在sizeof内部,所以数组名代表首元素地址,即a[0][0]的地址
  //所以a[0]+1代表数组第二个元素a[0][1]的地址,4/8
  printf("%d\n", sizeof(*(a[0] + 1)));  //4
  //对数组第二个元素解的地址引用得到第二个元素,整形大小4个字节
  printf("%d\n", sizeof(a + 1));    //4/8
  //a代表首元素即第一行的地址,a+1跳过一行,指向第二行,第二行的地址4/8
  printf("%d\n", sizeof(*(a + 1))); //16
  //第一行的地址+1指向第二行的地址,解引用得到第二行
  printf("%d\n", sizeof(&a[0] + 1));  //4/8
  //&a[0]取出第一行的地址,+1指向第二行的地址
  printf("%d\n", sizeof(*(&a[0] + 1))); //16
  //对第二行的地址解引用得到整个第二行
  printf("%d\n", sizeof(*a)); //16
  //a代表首元素即第一行的地址,解引用得到第一行
  printf("%d\n", sizeof(a[3])); //16
  //sizeof求数据大小时只关注数据的类型,不关注数据的内容
  //这里虽然这里a[3]越界了,但是根据a[3]的数据类型:int (*)[4] -- 数组指针,仍能求出a[3]的大小
  //a[3]代表一维数组的数组名单独放在sizeof内部代表整个数组的大小

总结:

1、数组名的意义

  • 数组名单独放在sizeof内部时表示整个数组;
  • &数组名取出的是整个数组的地址;
  • 其余情况数组名均表示首元素的地址;

2、指针类型的意义

  • 指针的类型决定了指针加减整数时跳过字节/元素的个数;
  • 指针的类型决定了指针解引用时的权限,即访问字节的个数(步长);

3、二维数组相关

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

推荐镜像

更多
  • DNS