承诺c指针 (1)指针是地址

(1)是地址

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

直观感受下。变量的地址

int main()
{
	int foo;
	int *foo_p;
	foo = 5;
	foo_p = &foo;
	printf("   foo...%d\n", foo);
	printf("*foo_p...%d\n", *foo_p);
	printf("  &foo...%p\n", &foo);
	printf(" foo_p...%p\n", foo_p);
	printf("&foo_p...%p\n", &foo_p);
	return 0;
}

执行

几点说明:

  1. %p中的p是pointer(指针)的意思。专门用于打印指针变量中的内容。
  2. 有时看到用%x打印指针的。尽管结果一样,但含义全然不同。

    %p:用合适的方式(通常是十六进制)输出指针变量中存放的还有一个变量的地址;%x:用十六进制的方式打印出变量的值。而且在我的环境中使用%x打印指针变量的话,会省略前面的0。

指针变量的示意图

左上角是变量名。右上角是变量地址。中间是变量存储的内容。

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

高阶指针

如二级指针:指向指针的指针。

int main()
{
	int foo = 5;
	int *foo_p = &foo;
	int **foo_pp = &foo_p;
	printf("     foo...%d\n", foo);
	printf("   &foo...%p\n", &foo);
	printf("  foo_p...%p\n", foo_p);
	printf(" &foo_p...%p\n", &foo_p);
	printf("  *foo_p...%d\n", *foo_p);
	printf(" foo_pp...%p\n", foo_pp);
	printf("&foo_pp...%p\n", &foo_pp);
	printf("*foo_pp...%p\n", *foo_pp);
	printf("**foo_pp...%d\n", **foo_pp);
	return 0;
}

执行

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

各变量的类型推导。foo_p是指针。且指向int,故foo_p的类型是int*。也就是在‘*‘前加入int;foo_pp也是指针,且指向foo_p。故foo_pp的类型是int**,也就是在‘*‘前加入int*。

更高阶的指针类型。以此类推。

看看在我的环境中各基本类型分配的内存大小

int main()
{
	printf("sizeof(char)...%d\n", sizeof(char));
	printf("sizeof(int)...%d\n", sizeof(int));
	printf("sizeof(float)...%d\n", sizeof(float));
	printf("sizeof(double)...%d\n", sizeof(double));
	printf("sizeof(int*)...%d\n", sizeof(int*));
	return 0;
}

执行

在我的环境中,指针类型分配的大小是 sizeof(int*)=4;也就是说用4个字节的大小来存储变量的地址,这也是眼下大多数环境下的结果。以后讨论基于这个结果。

至于在c标准中,没有规定指针类型的大小,详细大小依靠详细的环境。

关于 sizeof

首先必须指出:sizeof是操作符,而不是函数。

被误解为函数,可能是大多数情况下。我们都这样使用它:sizeof()。事实上这样用 sizeof 类型,如sizeof int也是能够的。

正确的使用是:假设Type是类型名。则sizeof(Type);假设Type是变量,则加不加括号,都能够。

探讨几个问题

(1)居然指针存放的是变量的地址,而在同一环境中地址是同种类型的整数,如4字节大小的,那为何还有指针类型的说法?

int main()
{
	int foo;
	int *int_p = &foo;
	//在c中以下这句代码会给出警告,但可执行;而在c++中是会直接报错的
	double *dou_p = &foo;
	foo = 5;
	printf("foo...%d\n", foo);
	printf("int_p...%p\n", int_p);
	printf("dou_p...%p\n", dou_p);
	printf("*int_p...%d\n", *int_p);
	printf("*int_p...%f\n", *int_p);
	printf("*dou_p...%d\n", *dou_p);
	printf("*dou_p...%f\n", *dou_p);
	return 0;
}

执行

这个结果非常让人凌乱!

为什么会出现这样的情况。关键在于:不同类型的变量有不同的存储方式。

如4字节的int和相同4字节的float,所分配的空间大小一样,但能够表示的数据范围有非常大差距。详细存储方式,大家可查下。

这就说明。在进行解引用时,必须指出相应的类型方式,才可正确获取变量值。

指针是派生类型,它的类型依靠它所指向的对象。

两个概念

指针的类型、指针所指向的类型

用实例说明:int *p;

(i)p是指针,它的类型是 int*

(ii)p是指针。它所指向的类型是 int

还有一个实例:int **p;

(i)p是指针。它的类型是 int**(二级指针,它的使用方法以后会讲到)

(ii)p是指针,它所指向的类型是 int*

方法非常easy:是不是指针类型,就看声明中有没有*;指针的类型就是去掉变量名后。剩下的部分;指针所指向的类型就是去掉变量名和离它近期的*。剩下的就是。

相同提醒我们:不可忽视编译器的警告!

(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 —— 选用输出宽度较小的格式输出实数

专栏文件夹:

版权声明:本文博主原创文章,转载,转载请注明出处。

时间: 2024-08-11 09:43:12

承诺c指针 (1)指针是地址的相关文章

对象布局已知时 C++ 对象指针的转换时地址调整

在我调试和研究 netscape 系浏览器插件开发时,注意到了这个问题.即,在对象布局已知(即对象之间具有继承关系)时,不同类型对象的指针进行转换(不管是隐式的从下向上转换,还是强制的从上到下转换)时,编译器会根据对象布局对相应的指针的值进行调整.不管是 microsoft 的编译器,还是 gcc 编译器都会做这个动作,因为这和 C++ 对象模型有关. 举一个简单的例子,如下代码: #include <stdio.h> class A { public: int x; void foo1()

指针、指针变量梳理,取地址与取值运算

#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { int a = 199; int *p; p = &a; printf("a=%d\n", a); printf("&a=%d\n", &a); printf("&p=%d\n", &p); printf("p=%d\n", p); printf(&q

Little-endian的一个好处:在变量指针转换的时候地址保持不变

Big-endian 的内存顺序和数字的书写顺序是一致的,方便阅读理解.Little-endian 在变量指针转换的时候地址保持不变,比如 int64* 转到 int32* 各有利弊,统一就好,目前看来是 little-endian成为主流了. ------------------------------------------------------------------------- 因为现在基本上遇不到PowerPC的服务器,所以我曾经比较变态的让通讯协议里全使用小端格式,然后用指针强制

指针&amp;指针的指针,地址&amp;地址的地址

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 int main(int argc, char* argv[]) 5 { 6 char *s[]={"man","woman","girl","boy","sister"}; 7 char* *q=NULL; //指针的指针 8 int k; 9

区别&lt;指针、指针的地址、指针的值&gt;

指针是指向某一个类型(内置的或者自定义的)的对象的变量. 通常我们说的“指针”,意指它所指向的对象的地址,也就是“指针的值”: 但是指针本身也是变量,也对应内存中的一块地方,因此“指针的地址”就是存储这个指针变量的内存的地址: 结合代码来看: /************************************************************************* > File Name: newd.cpp > Author: zeyuhu > Mail: [e

常量指针(指针指向的数值是常量)指针常量(指针指向的地址是无法改变的)

常量与常量指针 #include <iostream> using namespace std; int main() { int a = 3; const int *p = &a; cout << *p << endl; // *p = 20; // cout << *p << endl;//变量的值是常量,不能通过修改指向的变量的值,都是可以将指针进行指向别的地址. a = 20; cout << *p <<

详解 常量指针和指针常量

说一下 常量指针和指针常量 的区别. 常量指针 指向常量的指针,也就是说指针指向的对象是常量,指向的常量不能修改.指针不是一个常量, 可以把指针指向别一个常量. 常量指针是我们最常用的,一般声明形式如下: const int *p; int const *p; 例: int a(1), b(3); const int *p; // 或者是 int const *p; p = &a; std::cout << "address : " << p <&

数组指针和指针数组的区别

数组指针(也称行指针) 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长.也就是说执行p+1时,p要跨过n个整型数据的长度. 如要将二维数组赋给一指针,应这样赋值: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组. p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] p++;       //该语句执行过后,也就是

【转】让你不再害怕指针——C指针详解(经典,非常详细)

前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析.下面让我们先从简单的类型开始慢慢分析吧: [cpp] view plain copy int p; //这是一个普通的整型变量 int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,