概念

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指针 【温故】的更多相关文章

  1. (C初学) 对数组与指针的一些浅显的理解

    因为课堂上没听懂,又看不懂教科书(<C语言程序设计教程>第3版 谭浩强,张基温编著)上晦涩的表达方式,昨天晚上特意拿<C语言入门经典>这本书自己研究了一晚的数组与指针. 先来一 ...

  2. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

  3. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  4. C++虚函数和函数指针一起使用

    C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...

  5. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  6. c 数组与指针的使用注意事项

    数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...

  7. Marshal.Copy将指针拷贝给数组

    lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...

  8. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  9. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

随机推荐

  1. leetcode257

    /** * Definition for a binary tree node. * public class TreeNode { * public int val; * public TreeNo ...

  2. 小程序-Now you can provide attr "wx:key" for a "wx:for" to improve performance

    转自:https://www.cnblogs.com/xpwi/p/9878871.html 小程序开发-Now you can provide attr "wx:key" for ...

  3. 解决Notepad++ Plugin Manager无法加载插件的方法

    今天正好安装了Notepad++,结果发现Plugin Manager里插件一个也没有,网上对应的方法都没有,最后无意间看到Plugin Manager Settings 里的提示,试了一下居然成功了 ...

  4. eShopOnContainer 第一步

    运行结果截图: 操作流程: 1. git上clone 项目 windows版的docker并且安装成功,配置3核CPU,4G内存 vs 2017 (15.5)版本以上. 打开项目 eshopOnCon ...

  5. ConcurrentHashMap的简单理解

    一.效率低下的HashTable容器HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下.因为当一个线程访问HashTable的同 ...

  6. 133. Clone Graph (Graph, Map; DFS)

    Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...

  7. 利用 Chrome 原生工具进行网页长截图

    转自https://sspai.com/post/42193 要想使用截图功能,你需要首先确保 Chrome 已升级至 59 或更高版本.在想要截图的网页中,首先按下 ⌘Command + ⌥Opti ...

  8. python简单爬虫(一)

    学习python前纠结了下,到底是应该一个个知识点吃透,然后写些小程序.还是应该快速掌握基础语法,快速实践.思考后认为前者这么学习速度真心不高,于是花2天时间看了下python3的语法,虽然很多都不明 ...

  9. SpringMVC框架结构的图解、架构的处理流程以及三大组件的说明和使用

    1.1 框架结构 1.2 架构流程 1.用户发送请求至前端控制器DispatcherServlet: 2.DispatcherServlet收到请求调用HandlerMapping处理器映射器: 3. ...

  10. Python爬虫进阶四之PySpider的用法

    审时度势 PySpider 是一个我个人认为非常方便并且功能强大的爬虫框架,支持多线程爬取.JS动态解析,提供了可操作界面.出错重试.定时爬取等等的功能,使用非常人性化. 本篇内容通过跟我做一个好玩的 ...