指针就是地址

本文深入浅出地讲解了指针的基本概念,包括指针的定义、类型及高阶指针的应用。并通过示例代码详细解释了如何在C/C++中使用指针,以及不同类型指针之间的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先明确一个观点:指针就是地址。这是理解指针的起始一步。

直观感受下,变量的地址

[cpp]  view plain  copy
  1. int main()  
  2. {  
  3.     int foo;  
  4.     int *foo_p;  
  5.     foo = 5;  
  6.     foo_p = &foo;  
  7.     printf("   foo...%d\n", foo);  
  8.     printf("*foo_p...%d\n", *foo_p);  
  9.     printf("  &foo...%p\n", &foo);  
  10.     printf(" foo_p...%p\n", foo_p);  
  11.     printf("&foo_p...%p\n", &foo_p);  
  12.     return 0;  
  13. }  
运行


几点说明:

  1. %p中的p是pointer(指针)的意思,专门用于打印指针变量中的内容。
  2. 有时看到用%x打印指针的,虽然结果一样,但含义完全不同。%p:用合适的方式(一般是十六进制)输出指针变量中存放的另一个变量的地址;%x:用十六进制的方式打印出变量的值。并且在我的环境中使用%x打印指针变量的话,会省略前面的0。
指针变量的示意图

左上角是变量名,右上角是变量地址,中间是变量存储的内容。
可以这样来理解指针:指针是一种特殊的语言机制,它存放的是其它变量的地址,并且可以通过解引用操作符*,来获取该地址的内容。这也造成了一种指向的关系,如上图 foo_p->foo。

高阶指针
如二级指针:指向指针的指针。
[cpp]  view plain  copy
  1. int main()  
  2. {  
  3.     int foo = 5;  
  4.     int *foo_p = &foo;  
  5.     int **foo_pp = &foo_p;  
  6.     printf("     foo...%d\n", foo);  
  7.     printf("   &foo...%p\n", &foo);  
  8.     printf("  foo_p...%p\n", foo_p);  
  9.     printf(" &foo_p...%p\n", &foo_p);  
  10.     printf("  *foo_p...%d\n", *foo_p);  
  11.     printf(" foo_pp...%p\n", foo_pp);  
  12.     printf("&foo_pp...%p\n", &foo_pp);  
  13.     printf("*foo_pp...%p\n", *foo_pp);  
  14.     printf("**foo_pp...%d\n", **foo_pp);  
  15.     return 0;  
  16. }  
运行

由运行结果,画出内存示意图:

各变量的类型推导,foo_p是指针,且指向int,故foo_p的类型是int*,也就是在'*'前添加int;foo_pp也是指针,且指向foo_p,故foo_pp的类型是int**,也就是在'*'前添加int*。
更高阶的指针类型,以此类推。

看看在我的环境中各基本类型分配的内存大小
[cpp]  view plain  copy
  1. int main()  
  2. {  
  3.     printf("sizeof(char)...%d\n"sizeof(char));  
  4.     printf("sizeof(int)...%d\n"sizeof(int));  
  5.     printf("sizeof(float)...%d\n"sizeof(float));  
  6.     printf("sizeof(double)...%d\n"sizeof(double));  
  7.     printf("sizeof(int*)...%d\n"sizeof(int*));  
  8.     return 0;  
  9. }  
运行

在我的环境中,指针类型分配的大小是 sizeof(int*)=4;也就是说用4个字节的大小来存储变量的地址,这也是目前大多数环境下的结果。以后讨论基于这个结果。至于在c标准中,没有规定指针类型的大小,具体大小依靠具体的环境。

关于 sizeof
首先必须指出:sizeof是操作符,而不是函数。被误解为函数,可能是大多数情况下,我们都这样使用它:sizeof()。其实这样用 sizeof 类型,如sizeof int也是可以的。
正确的使用是:如果Type是类型名,则sizeof(Type);如果Type是变量,则加不加括号,都可以。

探讨几个问题
(1)竟然指针存放的是变量的地址,而在同一环境中地址是同种类型的整数,如4字节大小的,那为何还有指针类型的说法?
[cpp]  view plain  copy
  1. int main()  
  2. {  
  3.     int foo;  
  4.     int *int_p = &foo;  
  5.     //在c中下面这句代码会给出警告,但可运行;而在c++中是会直接报错的  
  6.     double *dou_p = &foo;  
  7.     foo = 5;  
  8.     printf("foo...%d\n", foo);  
  9.     printf("int_p...%p\n", int_p);  
  10.     printf("dou_p...%p\n", dou_p);  
  11.     printf("*int_p...%d\n", *int_p);  
  12.     printf("*int_p...%f\n", *int_p);  
  13.     printf("*dou_p...%d\n", *dou_p);  
  14.     printf("*dou_p...%f\n", *dou_p);  
  15.     return 0;  
  16. }  
运行


这个结果很让人凌乱!
为什么会出现这种情况,关键在于:不同类型的变量有不同的存储方式。如4字节的int和同样4字节的float,所分配的空间大小一样,但能够表示的数据范围有很大差距。具体存储方式,大家可查下。
这就说明,在进行解引用时,必须指出相应的类型方式,才可正确获取变量值。
指针是派生类型,它的类型依靠它所指向的对象。
两个概念
指针的类型、指针所指向的类型
用实例说明:int *p;
(i)p是指针,它的类型是 int*
(ii)p是指针,它所指向的类型是 int
另一个实例:int **p;
(i)p是指针,它的类型是 int**(二级指针,它的用法以后会讲到)
(ii)p是指针,它所指向的类型是 int*
方法很简单:是不是指针类型,就看声明中有没有*;指针的类型就是去掉变量名后,剩下的部分;指针所指向的类型就是去掉变量名和离它最近的*,剩下的就是。
同样提醒我们:不可忽视编译器的警告!

(2)空指针类型:void*
在ANSI C中提供了一种,可以接受任何类型的指针类型:void*(空指针类型)
int foo = 5;
void *p = &foo;   //这句话是不会报错的
printf("*p...%d\n", *p);   //这句话无法通过编译
不能通过编译的原因:如果仅仅知道变量的内存地址,但却不知道变量的类型,编译器也就不知道如何对这段地址上的内容进行解析,也就是无法解引用。

(3)printf()函数
printf(格式控制,输出表);
功能:按照规定格式输出指定数据。
“格式控制”是用双引号括起来的格式控制转换字符串。“输出表”中的数据可以是合法的常量、变量和表达式,要与“格式控制”中的格式字符一一对应。
几个格式输出符
%d —— 以带符号的十进制形式输出整数
%o —— 以无符号的八进制形式输出整数
%x —— 以无符号的十六进制形式输出整数
%u —— 以无符号的十进制形式输出整数
%c —— 以字符形式输出单个字符
%s —— 输出字符串
%f —— 以小数点形式输出单、双精度实数
%e —— 以标准指数形式输出单、双精度实数
%g —— 选用输出宽度较小的格式输出实数

<think>好的,我需要回答用户关于C语言指针指针变量的区别,以及为什么指针本质上是地址的问题。首先,我要理清这两个概念的定义,确保自己理解正确。根据提供的引用资料,指针是一个地址,而指针变量是存储这个地址的变量。也就是说,指针本身是一个值,而指针变量是存放这个值的容器。 接下来,我需要用用户容易理解的中文来解释这些概念。可能需要用类比,比如把指针比作房间号,指针变量比作存放房间号的纸条。这样用户可以通过日常生活中的例子来理解抽象的概念。 然后,关于指针为什么被称为地址,需要说明在计算机内存中,每个变量都有一个地址,这个地址就是指针指针变量则是用来保存这些地址的变量。这里要强调指针的本质就是内存地址,而指针变量是存储这个地址的变量。 还要注意区分指针指针变量的不同,避免混淆。例如,指针是具体的地址值,而指针变量是可以被赋值和修改的,存放不同地址的变量。这部分需要结合具体的例子,比如声明一个指针变量int *p;,然后p存储的是某个整型变量的地址。 最后,生成相关问题时要确保问题与主题相关,能够帮助用户进一步学习。比如,指针变量的声明和使用方法,或者指针在函数中的应用等。需要参考提供的引用资料中的知识点,确保问题的准确性和相关性。 在回答过程中,要检查是否符合用户给出的格式要求,比如使用$...$和$$...$$来包裹数学表达式或代码,但这个问题中没有数学表达式,所以可能不需要。同时,确保引用正确,在适当的位置添加引用标识,如[^1]、[^2]等。 现在,组织语言,分步骤解释,确保结构清晰,用户能够一步步理解。可能的结构是先定义指针指针变量,再对比两者的区别,最后解释指针作为地址的本质。然后附上相关问题,帮助用户深入思考。</think>### 指针指针变量的区别及本质解析 #### 一、指针指针变量的定义 1. **指针(Pointer)** 指针在C语言中**本质是内存地址**,例如变量`a`存储在内存地址`0x7ffd1234`,这个地址就是指针。它是数据在内存中的唯一标识,类似于现实中的“门牌号”[^1][^2][^3]。 2. **指针变量(Pointer Variable)** 指针变量是**专门存储指针地址)的变量**。例如声明`int *p;`时,`p`是一个指针变量,它可以存储某个整型变量的地址[^4]。 #### 二、核心区别 | 对比项 | 指针地址) | 指针变量 | |--------------|----------------------------------|------------------------------| | **本质** | 内存地址值(如`0x7ffd1234`) | 存储地址的变量 | | **可变性** | 不可变(地址由系统分配) | 可变(可重新指向其他地址) | | **语法示例** | `&a`(获取变量`a`的地址) | `int *p = &a;`(声明并赋值) | #### 三、为何说指针本质是地址? - **内存访问机制**:程序通过地址访问内存中的数据。例如,语句`printf("%d", *p);`中,`p`存储的地址被用来读取对应内存的值。 - **直接操作硬件**:指针允许直接读写特定内存位置,这是C语言高效性的核心体现。 #### 四、示例说明 ```c int a = 10; int *p = &a; // p是指针变量,存储a的地址指针) ``` - **指针**:`&a`是变量`a`的地址(例如`0x7ffd1234`)。 - **指针变量**:`p`是存放`&a`的变量,可通过`*p`访问`a`的值。 #### 五、常见混淆点 - **“指针”的两种含义**: - 狭义:指针 = 地址值(如`0x7ffd1234`)。 - 广义:指针变量也被简称为“指针”(需结合上下文区分)。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值