【C语言】指针数组测试题(1万字长文)(中)

简介: 【C语言】指针数组测试题(1万字长文)(中)

二维数组🦑

这就是数组的最后一道题。需要仔细的讲讲

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;
}
  • sizeof(a):这里是sizeof中出现数组名的情况,求的是整个数组的大小,数组3*4的个数是12个元素,类型都为int,12 *4 = 48 。
  • sizeof(a[0][0]):这是就是二维数组中第一个元素的写法,第一个元素类型为int,大小就是4。
  • sizeof(a[0]):这个就不一样了,我们说a[0]其实也可以写成这样*(a+0),a为数组名,数组名代表首元素地址,但是在二维数组中数组名代表第一行的地址,也就是说这个地址+1的话会跳过一行,而不是一个元素。但是这里只是+0就还是不变,我们知道a代表第一行的地址(把第一行看成是一维数组),和我们的一维数组的&arr是一样的都是拿到整个一维数组的地址。那么其实a+0可以看成就是&arr,为什么呢?因为都是拿到整个数组的地址,并且都是一维数组。那么*(a+0),就可以看成是 * (&arr),*又可以与&抵消就得到arr,这个arr我们就直接看成是第一行的数组名****就行。那么这道题的意思就是求第一行的总大小,是[4]*4=16。
    其实你也可以这样记忆,sizeof(a[0])代表求第一行的所有元素大小。
    那么a[0]就可以看成是第一行的数组名,并且是第一行的地址。

  • sizeof(a[0] + 1):a[0]作为第一行的数组名,并没有单独放在sizeof内部,也没有被取地址,按上面的分析方法a[0]代表第一行的数组名也是第一行的地址,所以a[0]就是数组首元素的地址,就是第一行第一个元素的地址,a[0]+1就是第一行第二个元素的地址,是地址那么在32位下是4,64位下是8。
  • sizeof(*(a[0] + 1)):a[0]+1就是第一行第二个元素的地址,解引用得到第二行第一个元素,大小为4。
  • sizeof(a + 1):a代表第一行地址,+1跳过第一行,但是还是地址,是地址那么在32位下是4,64位下是8。
  • sizeof(*(a + 1)):对第二行的地址解引用得到第二行,也可以写成这样:a[1],根据我所理解的,a[1]看成是第二行的数组名,并且是第二行的地址。解引用就得到第二行。大小为16。
  • sizeof(&a[0] + 1):a[0]我们知道是第一行的数组名对数组名取地址相当于拿到整个数组,然后+1跳过一行,但也还是地址,是地址那么在32位下是4,64位下是8。
  • sizeof(*(&a[0] + 1)):与多加了一个 *,代表对第二行的地址解引用,拿到第二行,对第二行求大小得16。
  • sizeof(*a):a代表二维数组数组名,也是第一行的地址,对第一行的地址解引用得到第一行。第一行大小为16。
  • sizeof(a[3]):最后是这个,我们看到我们行数最大也为2,为什么这里写3呢?
    这个代码是错误的吗?
int a[3][4] = { 0 };
• 1

其实不是,我们要知道一个知识点, sizeof在进行计算类型的大小时,它不会去看你括号里写的东西存不存在而是直接根据类型推得大小,a[3]就是第三行的数组名,即使没有第三行也会计算,数组名放在sizeof里得到第三行的大小,也是16。

小总结

二维数组中 :
a +1的+1是要跳过一行。(a是第一行的地址+1跳过一行,并且a是相对于二维数组而言)
a[0] +1的+1是要跳过一个元素。(a[0]是第一行的数组名,一维数组的数组名+1就跳过一个元素)
&a[0]+1的+1是要跳过一行。(&是拿到整个一维数组的地址再+1,肯定就跳过一行了)。

指针试题(共8道)

一二题

一 :

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

程序的结果是什么?

分析

  • a是整型数组5个元素,
  • int *ptr = (int *)(&a + 1);我们先说&a+1,我们知道&a得到的是整个数组的地址,那么+1就相当于跳过一个数组,为什么还要强制转换(int *)呢?因为&a相当于数组指针,与int *ptr 的类型不一样,所以要强制类型转换。现在已经分析完了,输出部分请看图。


  • 答案:

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

输出的结果是什么?

分析

我们知道p的值是0x100000,p+0x1呢? (unsigned long)p + 0x1); (unsigned int*)p + 0x1)又是多少?

  • 我们不要被吓到了,0x1其实就是1,而p是一个结构体指针变量,所以这个指针应该是这样的,struct Test *p;
    我们知道指针的类型决定指针的步长,那么现在结构体大小为20个字节,所以结构体指针+1就应该+20的地址。
    相当于0x100000+20。20用十进制表示就14。
    最后结果就是0x100014。
  • (unsigned long)p + 0x1);这里就改变的p的类型,之前是结构体指针现在强转为u long了,而u long咱们就把p不再看作一个指针变量了,就是一个普通的变量,相当于 int i = 0; i + 1。
  • 所以结果就是 0x100001。
  • (unsigned int*)p + 0x1),与上面一样,都是改变了指针的类型,u int *的大小也是 4个字节(32位),那么+1也是跳过4个字节。也相当于0x100000+0x4。
    结果就为0x100004。

三四题

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

输出的结果是什么?

分析:

  • 我们a是4个元素的整型数组, ptr1指向的是&a+1的地址处,就是跳过一个数组,这里强转是因为&a的类型相当于int (*)[4],最后将数组指针转为int *。
  • ptr2就不一样的了,a是数组名也是首元素地址,也可看作是一个int *类型,但是这里强转了,转为int 就相当于变成普通的变量加减而int *+1跳过4个字节int 类型+1,只跳过一个字节,最后再把类型转为int*就行了。

int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( "%d", p[0]);
 return 0;
}

输出的结果是什么?

分析:

这个就比上面的简单一些了,考察二维数组的知识点,

首先这个题目有个坑,二维数组初始化的时候,用(),就相当于逗号表达式,实际上应该是这样的, int a[3][2] = { 1, 3, 5};

我们知道a[0]就是代表第一行的数组名,数组名也是首元素地址,p[0]就相当于*(p +0),对p 解引用得到1。

目录
相关文章
|
6天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
18 3
|
18天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
44 0
|
5天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
13 2
|
14天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
23 1
|
20天前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
35 6
|
17天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
13 2
|
18天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
18天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
24天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
24天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。