C/C++拾遗(一):关于数组的指针和数组元素首地址的一道经典题

代码如下:

#include <stdio.h>
int main(void)
{
	int  a[5] = {1, 2, 3, 4, 5};
	int  *ptr = (int *)(&a+1);
	int *p1 = a;
	int *p2 = &a[0];
	int *p3 = (int *)(&a);

	if(p1 == p2){
		printf("p1 == p2\n");
	}else{
		printf("p1 != p2\n");
	}

	if(p1 == p3){
		printf("p1 == p3\n");
	}else{
		printf("p1 != p3\n");
	}

	if(p2 == p3){
		printf("p2 == p3\n");
	}else{
		printf("p2 != p3\n");
	}

	printf("%d %d\n",*(a+1),*(ptr-1));

	int *p4 = ++p1;
	int *p5 = ++p3;
	if(p4 == p5){
		printf("p4 == p5\n");
	}else{
		printf("p4 != p5\n");
	}
	return 0;
}

最终输出结果如下:

里面所有的判断都是相等,打印的两个值是2和5.

原因如下:

&a是数组的首地址,它的类型是int(*)[5],因此+1是加的是数组个数的步长。指针加1要根据指针自身类型加上一定的值, 不同类型的指针+1之后增加的大小不同。因此&a + 1后指向的地址对数组来说是越界的,注意前面有个int(*)又强制将他转为int*了。因此计算*(ptr - 1)的时候,ptr是个int类型的指针,减一等于往左移动sizeof(int*)个字节,因此又指向a[4]了,他的值等于&a[4].

为此杂家又对p4和p5作了验证,为啥结果p4会等于p5呢?原因就在于申请p3的时候对&a进行了强制类型转换,

int *p3 = (int *)(&a);

如果不加这个转换,是编译不过去的。加了转换之后p3等于p1也等于p2,他的类型跟另外两个一样都是int*类型的了,因此移动相同位后地址也是一样的。很多人纠结就纠结在&a、a、&a[0],根本原因在于对&a进行了强制类型(int*)转换。

时间: 2024-10-10 15:35:52

C/C++拾遗(一):关于数组的指针和数组元素首地址的一道经典题的相关文章

数组的初始化和二维数组、指针与数组

1.数组的初始化,比较简单,实例程如下: #include<stdio.h> # define M 12 int main(void){ int days[M]={31,28,31,30,31,30,31,30,30,31,30,31}; int i; for(i=0;i<M;i++) printf("Months %d has %2d days.\n",i+1,days[i]); return 0; } 运行结果如下: 2.未经初始化的数组: 实例程序: #incl

什么是指针?什么是数组?指针和数组的关系?

形象地讲,我们可以把计算机的内存看作一条长街上的一排房屋,每个房间都可以容纳数据并通过一个房号来表识.而表示每个房间房号的值我们可以称为地址.或许这样的比喻有局限性,毕竟真实地计算机内存是以数以万计的bit位组成. ⑴初始化: ①最简单的以 int *p 为例,初始化时内存里开辟了四个字节的空间. ▇▇▇▇ ②另一个声明 ,现在,我们有两个变量,下图中显示了后面那个未知内容的内存. char ch = 'a': char cp = &a; ▇→▇▓←(?) (cp)      (ch) ⑵&quo

GDB调试字符数组时指针和数组区别的体现

测试ftell函数时发现报错,先贴源码 // File Name: ftell.c #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { FILE* fp = fopen("myfile.in", "r"); if (fp == NULL) { perror("fopen error"); exit(1); } char buf[4

C语言--一维数组和多维数组数组名的含义

一.一维数组 对于一维数组,我们很容易理解数组名和元素地址的关系,即数组名代表数组首地址,亦即第一个元素的地址. 如定义数组int a[9]={1,2,3,4,5,6,7,8,9},则由上面的说明可得 a=&a[0],*a=a[0]: a+1=&a[1],*(a+1)=a[1]: ......... 二.二维数组 对于二维数组,我们一定要记住:它是数组的数组.如定义一个二维数组int b[3][4]={1,2,3,4,5,6,7,8,9,10,11,12},此时我们知道,可以把b看做是一个

指针、数组的理解与关系

一.指针的本质:变量,指针变量就是指针变量int *p:两个变量,一个p(指针变量本身)是int *类型的 另一个是*p(指针指向的那个变量)是int类型的注:指针说白了就是指针类型,前面定义的int类型是为了说明指针指向的那个数的类型,所以指针的解析方式都是按地址来解析的(不管你是char *还是double *,解析方式都是地址)而指向的那个数的类型就要看你怎么定义的了例如:int *aa是按照地址来解析的:*a则是按照int类型来解析的. (1)所有的类型的数据存储在内存中,都是按照二进制

C语言中的函数、数组与指针

1.函数:当程序很小的时候,我们可以使用一个main函数就能搞定,但当程序变大的时候,就超出了人的大脑承受范围,逻辑不清了,这时候就需要把一个大程序分成许多小的模块来组织,于是就出现了函数概念:  函数是C语言代码的基本组成部分,它是一个小的模块,整个程序由很多个功能独立的模块(函数)组成.这就是程序设计的基本分化方法: (1) 写一个函数的关键: 函数定义:函数的定义是这个函数的实现,函数定义中包含了函数体,函数体中的代码段决定了这个函数的功能: 函数声明:函数声明也称函数原型声明,函数的原型

C语言--&gt;(十一)指针于数组

知识点: • 指针与变量 (指向变量的指针)• 指针与函数 (地址传递) • 指针与数组 (指向数组的指针) • 指针与字符串 =================================数组的指针 1.什么是数组指针 1)数组的指针是指数组在内存的的起始位置 2)数组的第一个元素和数组的起始地址一致 2.数组名的本质 1)数组名本质上是一个地址常量,代表的是数组的首地址也就是第一个元素的地址 数组名表示表示数组的起始地址,不表示整个数组,不能对数组整体赋值. 3.数组名为一个指针常量,可

附录一 再论指针和数组

附录一 附录一 再论指针和数组 再论指针和数组 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 预习检查 链表单元有哪几个部分组成 如何申请链表单元,及释放链表单元 实现单链表插入的基本语法 简述一下快速排序基本理论要点 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Dat

C/C++ 知识点---数组与指针

数组和指针是两种不同的类型,数组具有确定数量的元素,而指针只是一个标量值.数组可以在某些情况下转换为指针,当数组名在表达式中使用时,编译器会把数组名转换为一个指针常量,是数组中的第一个元素的地址,类型就是数组元素的地址类型:指针的本质是一个与地址相关的复合类型,它的值是数据存放的位置(地址):数组的本质则是一系列的变量:数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变.指针可以随时指向任意类型的内存块,它的特征是"可变",所以我们常用指针来操作