指针与数组笔试题解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 指针与数组笔试题解析

一、关于数组名

数组名是数组首元素的地址,但是有2个例外:

1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节

2. &数组名 - 数组名也表示整个数组,取出的是整个数组的地址

除了这个2个例外,你见到的所有的数组名都表示首元素的地址

二、一维数组

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

三、字符数组

关于sizeof 与 strlen


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


sizeof 是操作符,不是函数


strlen 求字符串长度的,计算的是字符串中\0之前出现的字符的个数


统计到\0为止,如果没有看到\0,会继续往后找


strlen 是库函数 , 访问的实质是地址


ps:地址就是指针,指针就是地址

  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));//arr是数组首元素的地址,*arr 是首元素 - ‘a’ - 97
  //strlen就把‘a’的ASCII码值 97 当成了地址
  //err 会非法访问内存
     
  printf("%d\n", strlen(arr[1]));//arr[1] - 'b' - 98 - err
  
  printf("%d\n", strlen(&arr));//随机值,&arr是数组的地址,数组的地址也是指向数组起始位置,和第一个案例一样
  printf("%d\n", strlen(&arr + 1));//随机值
  printf("%d\n", strlen(&arr[0] + 1));//随机值
  
  
  printf("%d\n", sizeof(arr));//arr是数组名,并且是单独放在sizeof内部,计算的是数组总大小,单位是字节 - 6
  printf("%d\n", sizeof(arr + 0));//arr是数组名,并非单独放在sizeof内部,arr表示首元素的地址,arr+0还是首元素的地址
  //是地址大小就是4/8
    
  printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,sizeof计算的是首元素的大小,是1字节
  printf("%d\n", sizeof(arr[1]));//arr[1]是数组的第二个元素,sizeof(arr[1])计算的是第二个元素的大小,1个字节
  printf("%d\n", sizeof(&arr));//&arr- 取出的是数组的地址,sizeof(&arr))计算的是数组的地址的大小,是地址就是4/8字节
  printf("%d\n", sizeof(&arr + 1));//&arr是数组的地址,&arr+1跳过整个数组,指向'f'的后边,&arr+1的本质还是地址,是地址就是4/8字节
  printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是‘a’的地址,&arr[0]+1是'b'的地址,是地址就是4/8字节
char arr[] = "abcdef";
  printf("%d\n", sizeof(arr));//7 arr单独放在sizeof内部,表示整个数组,计算整个数组总大小,‘\0’也要算
  printf("%d\n", sizeof(arr + 0));// 4/8 arr没有单独放在sizeof内部,表示首元素地址,+0还是首元素地址,地址就是指针
  printf("%d\n", sizeof(*arr));//1 arr没有单独放在sizeof内部,*对arr解引用,表示首元素
  printf("%d\n", sizeof(arr[1]));//1 首元素大小
  printf("%d\n", sizeof(&arr));//4/8  arr取地址,表示整个数组的地址,是指针
  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 arr表示首元素地址,+0仍是首元素地址,计算的仍是整个字符串的长度
  printf("%d\n", strlen(*arr));//err *arr表示首元素,将arr的ASCI值 97 当做地址,非法访问
  printf("%d\n", strlen(arr[1]));//err 同上
  printf("%d\n", strlen(&arr));//6 表示整个字符串数组的地址
  printf("%d\n", strlen(&arr + 1));//suiji 调过整个数组,但不能确保 ‘\0’位置
  printf("%d\n", strlen(&arr[0] + 1));//5  第二个元素地址
char* p = "abcdef";
  printf("%d\n", sizeof(p));//p是指针变量,存放字符串的首元素地址,指针
  printf("%d\n", sizeof(p + 1));//4/8 p+1指向第二个元素的地址,仍是指针
  printf("%d\n", sizeof(*p));//1 表示首元素a
  printf("%d\n", sizeof(p[0]));//1 p[0]->*(p+0)->*p
  printf("%d\n", sizeof(&p));//4/8 表示指针变量p的地址,地址就是指针
  printf("%d\n", sizeof(&p + 1));//4/8 表示跳过整个p
  //值得注意的是&p 与&p+1 大小没有直接关系,因为不能保证p的地址中是否含有‘\0'
  //假如p的地址为0x 0012ff40 ‘\0’表示0,那么 00就表示‘\0'
  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));// 随机值 表示p的地址,相当于是一个二级指针,当无法确定 '\0 '的位置
  printf("%d\n", strlen(&p + 1));//随机值
  printf("%d\n", strlen(&p[0] + 1)); //5

四、二维数组

  int a[3][4] = { 0 };
  
  printf("%d\n", sizeof(a));//a是二维数组的数组名,数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
  //48
  printf("%d\n", sizeof(a[0][0]));//a[0][0]是一个整型元素,大小是4个字节
  printf("%d\n", sizeof(a[0]));//把二维数组的每一行看做一维数组的时候,a[0]是第一行的数组名,第一行的数组名单独放在sizeof内部
  //计算的是第一行的总大小,单位是字节 - 16
  printf("%d\n", sizeof(a[0] + 1));//a[0]虽然是第一行的数组名,但是并非单独放在sizeof内部
  //a[0]作为第一行的数组名并非表示整个第一行这个数组,a[0]就是第一行首元素的地址,a[0]--> &a[0][0] - int*
  //a[0]+1,跳过一个int,是a[0][1]的地址  4/8字节
  printf("%d\n", sizeof(*(a[0] + 1)));//a[0]+1是第一行第二个元素的地址,所以*(a[0]+1)就是a[0][1],大小是4个字节
  
  printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,没单独放在sizeof内部,也没有&,所以a就是数组首元素的地址
  //二维数组,我们把它想象成一维数组,它的第一个元素就是二维数组的第一行
  //a就是第一行的地址,a+1 是第二行的地址,是地址,大小就是 4/8 个字节
  //a - &a[0]
  //a+1 - &a[1]
  //a+2 - &a[2]
 
  printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,*(a+1) 找到的就是第二行,sizeof(*(a + 1))计算的就是第二行的大小
  //16
  //*(a+1) --> a[1]
  //sizeof(*(a + 1)) --> sizeof(a[1])
  //
  printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,sizeof(&a[0] + 1)计算的第二行地址大小
  //单位是字节 - 4/8
 
  printf("%d\n", sizeof(*(&a[0] + 1)));//&a[0] + 1是第二行的地址,*(&a[0] + 1)拿到的就是第二行,大小就是16个字节
  //*(&a[0]+1) --> a[1]
 
  printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址 - &a[0]
  //*a - 拿到的就是第一行 - 大小就是16个字节
  //*a -> *(a+0) -> a[0]
  //
  printf("%d\n", sizeof(a[3]));//代码没问题
  //a[3]是二维数组的第4行,虽然没有第四行,但是类型能够确定,大小就是确定的。大小就是一行的大小,单位是字节 - 16
  //能够分析出 a[3]的类型是:int [4] 
  printf("%d\n", sizeof(*( &a)));//48

总结:

数组名的意义:

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

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

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

五、指针笔试题

笔试题一:

​​​​​​​int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int* ptr = (int*)(&a + 1);
    printf("%d,%d", *(a + 1), *(ptr - 1));//2,5  a表示首元素地址,地址加一调过一个整型,指向第二个元素地址
    //取地址a,获得整个数组地址,加一调过整个数组,指向5的后面的地址,强制类型转换(不强有警告)。ptr减一,向后移动一个元素
    return 0;
}

笔试题二:

struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;//p是一个结构体变量指针
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
  p = (struct Test*)0x100000;//p的值为16进制数字,需强制类型转换为指针类型
  printf("%p\n", p + 0x1);//00100014,p为结构体指针,+1跳过一个结构体类型
  printf("%p\n", (unsigned long)p + 0x1);//00100001,强制类型转换为长整型,整型加一表示数值加一
  printf("%p\n", (unsigned int*)p + 0x1);// 00100004 强制类型转化为整型,整型指针加一表示调过一个整型,加4
  return 0;
}

笔试题三:

笔试题四:

int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//带‘()’的表达式最后一个值为表达式的解,
    //则a的实际值为:{{1,3},{5,0},{0,0}}
    int* p;
    p = a[0];
    printf("%d", p[0]);//p[0]此时表示第一行首元素地址,在sizeof中表示第一行地址
    return 0;
}

笔试题五:

int main()
{
    int a[5][5];
    int(*p)[4];//p的每行有4个元素,p[4][2]指向a中的第四行第三个元素,
    //相减得到字符个数的相反数-4
    p = a;
    printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    //指针相减得到的是中间的字符个数,将-4以地址形式打印
    return 0;
}

笔试题六:

int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int* ptr1 = (int*)(&aa + 1);//获得整个数组地址,加一跳过整个数组;
    //ptr-1指针大小减一,对地址解引用指向10
    int* ptr2 = (int*)(*(aa + 1));//aa表示首行元素地址,加一表示第二行首元素地址;
    //*ptr减一向后移动一个指针,指向5所在的地址
    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
    return 0;
}

笔试题七:

int main()
{
  char* c[] = { "ENTER","NEW","POINT","FIRST" };//c为指针变量,c中的元素类型为char*
  char** cp[] = { c + 3,c + 2,c + 1,c };//cp为指针变量,cp中的元素类型为char*,cp的类型为char**
  char*** cpp = cp;//cpp为指针变量,cpp中的元素类型为char**,cpp的类型为char***
  printf("%s\n", **++cpp);//POINT
  printf("%s\n", *-- * ++cpp + 3);//ER
  printf("%s\n", *cpp[-2] + 3);//ST
  printf("%s\n", cpp[-1][-1] + 1);//EW
  return 0;
}


相关文章
|
12天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
28 3
|
11天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
22 2
|
20天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
24 1
|
29天前
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
|
29天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
29天前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
22 0
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
3月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)

推荐镜像

更多