C指针 【温故】
概念
1 指针也是一个变量,做为指针变量的值是另一个变量的地址。指针存放的内容是一个地址,该地址指向一块内存空间
其一般形式为:
类型说明符 *变量名;
其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。
例如: int *p1;
表示p1是一个指针变量,它的值是某个整型变量的地址。或者说p1指向一个整型变量。至于p1究竟指向哪一个整型变量,应由向p1赋予的地址来决定。
2 图例解释
int i = ;//一个int变量,名字叫i
int *p;//定义了一个指向整数的指针变量
注意:
//在以下中
int i = ;//一个int变量,名字叫i
int *p;//定义了一个指向整数的指针变量 //p = 10;//错误,不可以把一个整数直接赋值给指针变量.
//c语言当中每个变量都有自己的内存地址。&符号就是取变量地址操作符. printf("%x",&i); //输出i的16进制地址
printf("%d",*p); //输出i的值
printf("%x",&*p); //输出i的16进制地址
printf("%x",&p); //输出p的地址,注意,指针也有自己的内存地址
printf("%x",p); //输出i的16进制地址
切记,指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针。
3 指针变量的引用
指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误。在C语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。
两个有关的运算符:
1) &:取地址运算符。
2) *:指针运算符(或称“间接访问” 运算符)。
C语言中提供了地址运算符&来表示变量的地址。
其一般形式为:
&变量名;
如&a表示变量a的地址,&b表示变量b的地址。变量本身必须预先说明。
设有指向整型变量的指针变量p,如要把整型变量a 的地址赋予p可以有以下两种方式:
(1) 指针变量初始化的方法
int a;
int *p=&a;
(2) 赋值语句的方法
int a;
int *p;
p=&a;
不允许把一个数赋予指针变量,故下面的赋值是错误的:
int *p;
p=1000;
4 野指针
定义了一个指向int的指针变量;没有赋初值,就是个野指针,指向什么内存地址不知道
int *p3;
* 野指针的危害只是程序本身,不会影响到操作系统。
* 如果你做的是一个驱动程序或者内核代码,那么可能是致命的,操作系统崩溃
* 野指针也叫悬空指针,不能给野指针指向的内存区域赋值。
注意:一个指向NULL的指针,我们称之为空指针(也就是说野指针),意味着这个指针不指向任何一个变量。
5 无类型指针
定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将void *转化为其他类型指针,也可以用(void *)将其他类型指针强制转化为void类型指针。
void *p
在C语言当中,可以将任何一种地址赋值给void *指针
例如:
void *p4;//定义了一个无类型的指针。
p4 = &i;//可以将任意类型的地址赋值给void *
//p1 = p4;//(在C语言中可以将void *赋给任意类型的指针变量).但C++这个语句是非法的
6 指针变量作为函数参数
函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。
例:输入的两个整数按大小顺序输出
swap(int *p1,int *p2)
{int temp;
temp=*p1;
*p1=*p2;
*p2=temp;
}
main()
{
int a,b;
int *pointer_1,*pointer_2;
scanf("%d,%d",&a,&b);
pointer_1=&a;pointer_2=&b;
if(a<b) swap(pointer_1,pointer_2);
printf("\n%d,%d\n",a,b);
}
说明:
swap是用户定义的函数,它的作用是交换两个变量(a和b)的值。swap函数的形参p1、p2是指针变量。程序运行时,先执行main函数,输入a和b的值。然后将a和b的地址分别赋给指针变量pointer_1和pointer_2,使pointer_1指向a,pointer_2指向b。
7 数组指针
一个变量有地址,一个数组包含若干个元素,每个元素在内存中都有地址。
int a[]; int *p = a; p和&a[]的地址是否相同?
相同
在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址。
int array[] = { , , , , , };//array[0]的值是6
int *p = &array[];//p指向了数组的第一个元素的地址
int *p1 = array;//p1指向了数组的首地址.
//*p和*p1是一样的。
8 通过指针引用数组元素
如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。
如果p的初值为&a[0],则:
1) p+i和a+i就是a[i]的地址,或者说它们指向a数组的第i个元素。
2) *(p+i)或*(a+i)就是p+i或a+i所指向的数组元素,即a[i]。例如,*(p+5)或*(a+5)就是a[5]。
3) 指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价。
根据以上叙述,引用一个数组元素可以用:
1) 下标法,即用a[i]形式访问数组元素。在前面介绍数组时都是采用这种方法。
2) 指针法,即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数组的指针变量,其处值p=a。
例:输出数组中的全部元素。(下标法)
main(){
int a[],i;
for(i=;i<;i++)
a[i]=i;
for(i=;i<;i++)
printf("a[%d]=%d\n",i,a[i]);
}
输出数组中的全部元素。(通过数组名计算元素的地址,找出元素的值)
main(){
int a[],i;
for(i=;i<;i++)
*(a+i)=i;
for(i=;i<;i++)
printf("a[%d]=%d\n",i,*(a+i));
}
输出数组中的全部元素。(用指针变量指向元素)
main(){
int a[],I,*p;
p=a;
for(i=;i<;i++)
*(p+i)=i;
for(i=;i<;i++)
printf("a[%d]=%d\n",i,*(p+i));
}
main(){
int a[],i,*p=a;
for(i=;i<;){
*p=i;
printf("a[%d]=%d\n",i++,*p++);
}
}
注意:
1) 指针变量可以实现本身的值的改变。如p++是合法的;而a++是错误的。因为a是数组名,它是数组的首地址,是常量。
【感谢谭浩强老师的《C语言》】
C指针 【温故】的更多相关文章
- (C初学) 对数组与指针的一些浅显的理解
因为课堂上没听懂,又看不懂教科书(<C语言程序设计教程>第3版 谭浩强,张基温编著)上晦涩的表达方式,昨天晚上特意拿<C语言入门经典>这本书自己研究了一晚的数组与指针. 先来一 ...
- TODO:Golang指针使用注意事项
TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++虚函数和函数指针一起使用
C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- c 数组与指针的使用注意事项
数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...
- Marshal.Copy将指针拷贝给数组
lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
随机推荐
- linux学习(别人指出来的), 回头有针对性的学下!
应该是 会linux 基本操作吧linux 安装 lamp lnmp php拓展这些基本都得会把知道subversion 和 github 这俩吧windows的代码同步到linux上无需ftp 会跟 ...
- (4)activiti工作流引擎之uel表达式
有了前面几章,我们肯定有一定的困惑,activiti如何与实际业务整合,比如一条采购单,如何跟一个流程实例互相关联起来? 这里就需要使用到activiti启动流程实例时设置一个流程实例的busines ...
- javascript中所谓的“坑”收录
坑一: // 反例myname = "global"; // 全局变量function func() { alert(myname); // "undefined&quo ...
- Android SDK Manager检查更新时遇到Failed to fetch URL xxxxxxx reason: Connection to xxxxxx的错误的解决办法!
首先说明的是这个问题并不是每个人都存在,但是我和我的一个同学都有这种情况,所以我同学百度了一下,找出了解决办法. 问题描述: 使用Android SDK Manager检查在线更新,提示以下错误: & ...
- 通过Jenkins自动构建dubbo服务时的问题汇总
最近接触新的dubbo项目,项目初始时,测试环境的提供者服务发布较频繁,奈何公司又没有自动发布工具,遂自己在测试环境中搭建了Jenkins用于dubbo服务的发布.由于第一次使用,过程中也遇到了一些问 ...
- DataTable记录
DataTable dt2 = dt.Copy();//复制结构和数据 //复制结构,不要数据 DataTable dt2 = new DataTable(); for (int i = 0; i & ...
- Linux confluence5.8.10 wiki安装
选择首先需要java环境 其次需要mysql mysql安装请参考: http://www.cnblogs.com/syuf/p/7818710.html 安装好mysql之后,创建一个库 # mys ...
- DataStage 六、安装和部署集群环境
DataStage序列文章 DataStage 一.安装 DataStage 二.InfoSphere Information Server进程的启动和停止 DataStage 三.配置ODBC Da ...
- 友盟统计小白教程:创建应用,申请appkey
上回书讲到,我们已经和一个靠谱的人选择一个靠谱的统计平台注册了一个帐号,下面就该创建一个应用了. 介绍一个基础知识: appkey:友盟识别app的唯一标识,目前友盟平台上超过500000款App,每 ...
- 1 web应用-http协议-web框架
web 应用 Web 应用程序是一种可以通过 Web 访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式 C/S.B/S.C/S ...