c语言分层理解(c语言指针笔试题解析)(2)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 前言经过了一天的写作,终于完成了这一篇,对指针进行了练习,感觉很爽,分享一下!还望大佬多多关注!1. 一维数组和指针

3. 二维数组和指针

3.1 例题

#include <stdio.h>
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;
}

3.2 解析

#include <stdio.h>
int main()
{
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));
  //结果:48字节
  //解释:a是数组名,数组名单独放在sizeof内部,计算的是整个二维数组大小,所以sizeof(a)=4*3*4=48,单位是字节
  printf("%d\n", sizeof(a[0][0]));
  //结果:4字节
  //解释:a[0][0]得到的第一行第一列的元素,元素类型是int,所以sizeof(a[0][0])=sizeof(int)=4,单位是字节
  printf("%d\n", sizeof(a[0]));
  //结果:16字节
  //解释:a[0]表示二维数组的第一行,第一行是一个有四个元素的一维数组,在二维数组中a[0]就相当于一维数组名,
  //     数组名单独放在sizeof内部,计算的是整个一维数组的大小,a[0]类型是int [4],所以sizeof(a[0])=4*4=16,单位是字节
  printf("%d\n", sizeof(a[0] + 1));
  //结果:4/8字节
  //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,在二维数组中a[0]就相当于一维数组名,并不是单独放在二维数组中,所以他就是一维数组首元素地址,地址就是指针,
  //     指针类型是int*,a[0]+1就是跳过一个int大小,得到a[0][1]的地址,地址就是指针,所以sizeof(a[0]+1)计算的是整个指针的大小,单位是字节
  printf("%d\n", sizeof(*(a[0] + 1)));
  //结果:4字节
  //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,在二维数组中a[0]就相当于一维数组名,并不是单独放在二维数组中,所以他就是一维数组首元素地址,地址就是指针,
  //     指针类型是int*,a[0]+1就是跳过一个int大小,得到a[0][1]的地址,地址就是指针,拿到a[0][1]这个元素,元素类型是int类型,所以sizeof(*(a[0]+1))=sizeof(int),单位是字节
  printf("%d\n", sizeof(a + 1));
  //结果:4/8字节
  //解释:a是数组名,并没有单独放在sizeof内部,所以a是二维数组首行地址,地址就是指针,类型是int (*arr)[4],a+1跳过一个有4个int类型元素的数组,得到a[1],
  //     也就是二维数组第二行地址,地址就是指针,所以sizeof(a+1)计算的是指针大小
  printf("%d\n", sizeof(*(a + 1)));
  //结果:16字节
  //解释:a是数组名,并没有单独放在sizeof内部,所以a是二维数组首行地址,地址就是指针,类型是int (*arr)[4],a+1跳过一个有4个int类型元素的数组,得到a[1],
  //     也就是二维数组第二行地址,对其解引用得到的是二维数组中第二行一维数组,sizeof(*(a+1))=sizeof(a[1])=4*4=16,单位是字节
  printf("%d\n", sizeof(&a[0] + 1));
  //结果:4/8字节
  //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,&a[0]得到的是二维数组的第一行整个数组的地址,地址就是指针,指针类型是int (*arr)[4],&a[0]+1跳过一个一维数组的大小,
  //     得到的就是二维数组中第二行整个一维数组的地址,地址就是指针,所以sizeof(&a[0]+1)计算的就是指针的大小
  printf("%d\n", sizeof(*(&a[0] + 1)));
  //结果:16字节
  //解释:a[0]表示二维数组的第一行,,第一行是一个有四个元素的一维数组,&a[0]得到的是二维数组的第一行整个数组的地址,地址就是指针,指针类型是int (*arr)[4],&a[0]+1跳过一个一维数组的大小,
  //     得到的就是二维数组中第二行整个一维数组的地址,*(&a[0]+1)得到的就是二维数组中的第二行一维数组,sizeof(*(&a[0] + 1))=sizeof(a[1])=4*4=16,单位是字节
  printf("%d\n", sizeof(*a));
  //结果:16字节
  //解释:a是二维数组的数组名,数组名不没有单独放在sizeof内部,所以a是第一行的地址,地址就是指针,指针类型是int (*arr)[4],
  //     *a得到的就是二维数组中的整个第一行一维数组,sizeof(*a)=sizeof(a[0])=4*4=16,单位是字节
  printf("%d\n", sizeof(a[3]));
  //结果: 16字节
  //解释:a[3]在二维数组中就相当于拿到下标为3的一整行一维数组,a[3]也就是第四行的一维数组名,数组名在sizeof内部,计算的是整个数组的大小,
  //     虽然没有数组没有第四行,但是可以给a[3]预分配一个空间,所以给a[3]预分配一个int [4]的空间,sizeof计算的只是类型的大小,这里a[3]的类型就是int [4],所以sizeof(a[3])=4*4=16,单位是字节
  return 0;
}

3.3 输出结果

3.3.1 32位平台

8874ee4b2ed73fd478c2d8987647f9b9.png

3.3.2 64位平台

0a7a9343ecc578d1bf97971df96e2511.png

4. 例题4.指针

4.1 例题

#include <stdio.h>
int main()
{
  int a[5] = { 1, 2, 3, 4, 5 };
  int* ptr = (int*)(&a + 1);
  printf("%d,%d", *(a + 1), *(ptr - 1));
  return 0;
}

4.2 解析

b6fd378f4ec7c2c8a44e2cf268775d14.png

5. 例题5.指针

5.1 例题

struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
  p = (struct Test*)0x100000;
  printf("%p\n", p + 0x1);
  printf("%p\n", (unsigned long)p + 0x1);
  printf("%p\n", (unsigned int*)p + 0x1);
  return 0;
}

5.2 解析

ccfe48d6e6d3cda20226ee90445220fe.png

6. 例题6.指针

6.1 例题

#include <stdio.h>
int main()
{
  int a[4] = { 1, 2, 3, 4 };
  int* ptr1 = (int*)(&a + 1);
  int* ptr2 = (int*)((int)a + 1);
  printf("%x,%x", ptr1[-1], *ptr2);
  return 0;
}

6.2 解析

fcc5dae4c0261debea1862e20a588962.png

7. 例题7.指针

7.1 例题

#include <stdio.h>
int main()
{
  int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  int* p;
  p = a[0];
  printf("%d", p[0]);
  return 0;
}

7.2 解析

ac1fd92cc463cadc227c4149757d1beb.png

8. 例题8.指针

8.1 例题

#include <stdio.h>
int main()
{
  int a[5][5];
  int(*p)[4];
  p = a;
  printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
  return 0;
}

8.2 解析

4d8fb7eebd7c965c0effbb807a76ba29.png

9. 例题9.指针

9.1 例题

#include <stdio.h>
int main()
{
  int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  int* ptr1 = (int*)(&aa + 1);
  int* ptr2 = (int*)(*(aa + 1));
  printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}

9.2 解析

d8feb9d62ebed8a635ae9c9a8daf1853.png

10. 例题10.指针

10.1 例题

#include <stdio.h>
int main()
{
  char* a[] = { "work","at","alibaba" };
  char** pa = a;
  pa++;
  printf("%s\n", *pa);
  return 0;
}

10.2 解析

b88a46054400d5101bf154b0834c3718.png

11. 例题11.指针

11.1 例题

#include <stdio.h>
int main()
{
  char* c[] = { "ENTER","NEW","POINT","FIRST" };
  char** cp[] = { c + 3,c + 2,c + 1,c };
  char*** cpp = cp;
  printf("%s\n", **++cpp);
  printf("%s\n", *-- * ++cpp + 3);
  printf("%s\n", *cpp[-2] + 3);
  printf("%s\n", cpp[-1][-1] + 1);
  return 0;
}

11.2 解析

![](https://ucc.alicdn.com/images/user-upload-01/img_convert/24baf958d698b0ac8197755d5762942d.png

12. 总结

sizeof计算大小的时候,首先关心计算对象,是一个变量还是一个数组名,还是什么,这里重点放在计算数组上,如果sizeof内部包含一个单独的数组名,说明这个sizeof计算的是整个数组的大小,否则不是,单位是字节,这个很重要,假如说sizeof(arr[2][2]),这个二维数组的类型是int,那么这个sizeof(arr[2][2])= 224=16,单位是字节。计算字符串数组的时候,sizeof(arr)计算包含’\0’的计算,'\0’也是占空间。

strlen计算的是’\0’之前的元素个数,在数组中,数组中不包含’\0’的话,一般这里就是随机值,另外注意strlen库函数再求一个字符解引用的时候会出现报错,原因就是非法访问。

&数组名,取的是整个数组的地址,&arr+1也是跳过整个数组的大小

对指针进行解引用的时候,要关注指针对应的元素类型,这决定了拿取多少个字节的空间,指针±操作的时候要关注类型,决定步长。







相关文章
|
1月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
167 14
|
1月前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
85 9
|
1月前
|
存储 编译器 C语言
【C语言】数据类型全解析:编程效率提升的秘诀
在C语言中,合理选择和使用数据类型是编程的关键。通过深入理解基本数据类型和派生数据类型,掌握类型限定符和扩展技巧,可以编写出高效、稳定、可维护的代码。无论是在普通应用还是嵌入式系统中,数据类型的合理使用都能显著提升程序的性能和可靠性。
63 8
|
1月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
665 6
|
1月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
60 5
|
1月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
52 5
|
1月前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
83 0
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
218 13
|
3月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
47 0
|
4月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
178 4

热门文章

最新文章

推荐镜像

更多