C语言指针的初始化和赋值
1、指针的初始化
指针初始化时,“=”的右操作数必须为内存中数据的地址,不能够是变量,也不能够直接用整型地址值(可是int*p=0;除外,该语句表示指针为空)。此时,*p仅仅是表示定义的是个指针变量,并没有间接取值的意思。
比如:
int a = 25;
int *ptr = &a;
int b[10];
int *point = b;
int *p = &b[0];
假设:int *p;
*p = 7;
则编译器(vs2008)会提示The variable 'p' is being used without being initialized.即使用了未初始化的变量p。
由于p是指向7所在的地址,*p = 7给p所指向的内存赋值,p没有赋值,所以p所指向的内存位置是随机的,没有初始化的。
int k;
int *p;
p = &k; //给p赋值
*p = 7; //给p所指向的内存赋值,即k= 7
2、指针的赋值
int *p;
int a;
int b[1];
p = &a;
p = b;
指针的赋值,“=”的左操作数能够是*p,也能够是p。
当“=”的左操作数是*p时,改变的是p所指向的地址存放的数据;
当“=”的左操作数是p时,改变的是p所指向的地址。
数组的变量名b表示该数组的首地址,因此p=b;也是正确的
同类型的指针赋值:
int val1 = 18,val2 = 19;
int *p1,*p2;
p1 = &val1;
p2 = &val2;
p1 = p2; //注意啦,p1指向了val2,而没有指向val1
备注:字符串与指针的初始化和赋值
初始化:
char *cp = "abcdefg"; //这个初始化过程,是将指针cp指向字符串的首地址,而并非传递字符串的值。由于,在C语言里面,没有总体处理一个字符串的机制
赋值:
cp = "abcdefg";
*cp=”abcdefg” ;//错误!字符串常量传递的是它的首地址,不能够通过*cp改动该字符串的值,由于该字符串为常量,而它仅仅是简单的将指针指向该字符串常量
3、指针常量
在C语言中没有一种内建(built-in)的方法去表示指针常量,所以当我们使用它的时候通常先写成整型常量的形式,然后再通过强制类型转换把它转换成对应的类型,如:int * , double * , char *等。 所以后面所看到的的做法是不行的: int *p = 0x12345678 ; 正确的方式应为:int *p = (int *) 0x12345678; 要注意指针中仅仅能存放地址,不能将一个非0值整型常量表达式或者其它非地址类型的数据赋给一个指针,原因就在此。在大多数计算机中,内存地址确实是以无符号整型数来表示的,并且多以16进制表示,但我们在C语言中不能用整型数去表示地址,仅仅能用指针常量来表示,由于它是被用来赋给一个指针的。
对于这个赋值问题还能够换一个角度去理解,在C语言中,使用赋值操作符时,赋值操作符左边和右边的表达式类型应该是同样的,假设不是,赋值操作符将试图把右边表达式的值转换为左边的类型。所以假设写出int *p = 0x12345678 ; 这条语句编译器会报错:'=' : cannot convert from ' const int ' to ' int * ' ,由于赋值操作符左边和右边的表达式的类型应该同样,而0x12345678是int型常量,p是一个指向int型的指针,两者类型不同,所以正确的方式是:int
*p = (int *) 0x12345678 ;
4、指针初始化补充
ANSI C定义了零指针常量的概念:一个具有0值的整形常量表达式,或者此类表达式被强制转换为void *类型,则称为空指针常量,它能够用来初始化或赋给不论什么类型的指针。也就是说,我们能够将0、0L、'/0'、2–2、0*5以及(void *)0赋给一个不论什么类型的指针,此后这个指针就成为一个空指针,由系统保证空指针不指向不论什么对象或函数。
ANSI C还定义了一个宏NULL,用来表示空指针常量。大多数C语言的实现中NULL是採用后面这样的方式定义的:#define NULL ((void *)0)。
对指针进行初始化时经常使用的有下面几种方式:
1.採用NULL或空指针常量,如:int *p = NULL;或 char *p = 2-2; 或float *p = 0;
2.取一个对象的地址然后赋给一个指针,如:int i = 3; int *ip = &i;
3.将一个指针常量赋给一个指针,如:long *p = (long *)0xfffffff0;
4.将一个T类型数组的名字赋给一个同样类型的指针,如:char ary[100]; char *cp = ary;
5.将一个指针的地址赋给一个指针,如:int i = 3; int *ip = &i;int **pp = &ip;
6.将一个字符串常量赋给一个字符指针,如:char *cp = “abcdefg”;
对指针进行初始化或赋值的实质是将一个地址或同类型(或相兼容的类型)的指针赋给它,而无论这个地址是怎么取得的。要注意的是:对于一个不确定要指向何种类型的指针,在定义它之后最好把它初始化为NULL,并在解引用这个指针时对它进行检验,防止解引用空指针。另外,为程序中不论什么新创建的变量提供一个合法的初始值是一个好习惯,它能够帮你避免一些不必要的麻烦。
5、void *型指针
ANSI C定义了一种void *型指针,表示定义一个指针,但不指定它指向何种类型的数据。void *型指针作为一种通用的指针,能够和其他不论什么类型的指针(函数指针除外)相互转化而不须要类型强制转换,但不能对它进行解引用及下标操作。C语言中的malloc函数的返回值就是一个void *型指针,我们能够把它直接赋给一个其他类型的指针,但从安全的编程风格角度以及兼容性上讲,不妨将返回的指针强制转换为所需的类型,另外,malloc在无法满足请求时会通过返回一个空指针来作为“内存分配失败”的信号,所以要注意返回值指针的判空。
6、指向指针的指针
在指针初始化的第5种方式中提到了用一个指针的地址来初始化一个指针。回顾一下上一讲的内容:指针是一种变量,它也有自己的地址,所以它本身也是可用指针指向的对象。我们能够将指针的地址存放在还有一个指针中,如:
int i = 5000;
int *pi = &i;
int **ppi = π
此时的ppi即是一个指向指针的指针,下图表示了这些对象:
i的地址为108,pi的内容就是i的地址,而pi的地址为104,ppi的内容即是pi的地址。对ppi解引用照常会得到ppi所指的对象,所获得的对象是指向int型变量的指针pi。想要真正地訪问到i.,必须对ppi进行两次解引用,如以下代码所看到的:
printf("%d", i );
printf("%d", *pi );
printf("%d", **ppi );
以上三条语句的输出均为5000。
C语言指针的初始化和赋值的更多相关文章
- C语言指针、地址、赋值三者含义
先来一个观点.大家先看看对不对 按:在CSDN论坛上,有位坛友提到这个问题: ==================================== 先看一段代码: #include<stdi ...
- c语言结构体指针必须初始化
先说结论 结构体指针需要初始化 结构体指针的成员指针同样需要初始化 结构体变量定义的时候就已经分配了内存空间,而上面两个确没有 struct test{ int i; struct buf *p;} ...
- C语言结构体数组内带字符数组初始化和赋值
1.首先定义结构体数组: typedef struct BleAndTspRmtCmd{ char terminal[3]; char note[3]; char rmtCmd[10]; char c ...
- 不可或缺 Windows Native (7) - C 语言: 指针
[源码下载] 不可或缺 Windows Native (7) - C 语言: 指针 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 指针 示例cPointer.h #i ...
- C语言指针学习
C语言学过好久了,对于其中的指针却没有非常明确的认识,趁着有机会来好好学习一下,总结一下学过的知识,知识来自C语言指针详解一文 一:指针的概念 指针是一个特殊的变量,里面存储的数值是内存里的一个地址. ...
- c语言指针详解(转载)
转自(http://blog.csdn.net/ad_ad_ad/article/details/1522145) 指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指 ...
- C语言指针5分钟教程
指针.引用和取值 什么是指针?什么是内存地址?什么叫做指针的取值?指针是一个存储计算机内存地址的变量.在这份教程里“引用”表示计算机内存地址.从指针指向的内 存读取数据称作指针的取值.指针可以指向某些 ...
- C程序设计语言--指针和引用的区别
在看了一篇文章以后,http://coolshell.cn/articles/7992.html,说的是C和C++之间的缺陷,当然这篇文章说的非常高深了.所以就找了一些资料,分析了这两者的区别 在&l ...
- c语言指针具体解释
指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最基本的风格之中的一个.利用指针变量能够表示各种数据结构: 能非常方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编出精练而高 ...
随机推荐
- LeetCode: Longest Consecutive Sequence [128]
[题目] Given an unsorted array of integers, find the length of the longest consecutive elements sequen ...
- Linux下Samba的配置
前言: 为了实现windows 和 Linux以及其它操作系统之间的资源共享,软件商推出nfs 和samba两种解决方案.因为市场上缺乏象pc-nfs那样的client工具,使得Linux和windo ...
- Zabbix使用外部邮箱服务器发送邮件报警
本来是想自己写一篇文章的,但是看到发现网上有写的不错的,于是乎又抄别人的文章,作为记录. 使用外部邮箱来发生邮件明显好处就是防止其他邮箱服务器当垃圾邮件处理,另一方面能降低收邮件延迟. 下面开始进行使 ...
- dtree基础
最近用到了dtree来建立树,纠结过好久后,终于有了些门道,下面的总结希望对咪咪们有些帮助: dtree用来建立静态树或者动态树都是很方便的,老外给提供了整个的JS,然后我们只是操心这个树中存放的元素 ...
- Android零碎知识点总结
1 简单的跨进程通信可以用Messenger类,不用AIDL. 2 当一个Service没有action时,它默认是exported="false"的,其它进程用它的包名和类名构造 ...
- 基础命名空间:序列化 System.Runtime.Serialization
对象通常都有状态(state),从一个对象中抽取这种状态,不论是将它存储于某地,还是通过网络传送,这种抽取动作称为“将一个对象序列化”,而反向处理过程,从一个被序列化的状态重建一个对象即为反序列化. ...
- pca图像识别
代码下载:基于PCA(主成分分析)的人脸识别 人脸识别是一个有监督学习过程,首先利用训练集构造一个人脸模型,然后将测试集与训练集进行匹配,找到与之对应的训练集头像.最容易的方式是直接利用欧式距离计算测 ...
- JSP脚本元素上机手册
L3 <JSP基础>上机手册 内容回顾 脚本元素<%! %> <%= %> <% %> 注释元素 JSP指令元素 JSP动作元素 上机目标 掌握脚本元素 ...
- UltraEdit v17.10.0,注册机,注册码
1,UltraEdit注册机 :点击下载 2,断掉网络,进入UltraEdit软件,依次点击:帮助——注册/激活——激活,会提示你进行脱机激活,点击脱机激活后,将用户码1和用户码2 分别输入注册机的u ...
- linux下挂载CDROM命令
cdrom装载在/dev/cdrom 下面. 挂载时在权限范围内建立一个文件夹.例如mkdir /home/dang/cdtmp 然后执行 mount dev/cdrom /home/dang/cdt ...