c语言中认识指针

来源:互联网 发布:少男的喜欢lofter乐乎 编辑:程序博客网 时间:2024/05/01 17:49
地址和变量的概念

指针

作用:
1、表示复杂的数据结果(eg:链表、树、)
2、能动态分配内存
3、方便的使用字符串
4、有效而方便使用字符串
5、有效而方便的使用数组
&&&调用函数的时候能够获得1 个以上的结果。
6、能够直接处理单元地址等

总结:可以看到可以很直接的接触到计算机的硬件的内容进行操作。

1、数据的存储和读取:
定义一个变量,程序在编译的时候,会给这个变量分配内存单元。
(依据:系统会根据程序中定义的变量的类型,分配一定的长度空间。eg:32位机,int分配2位字节,char分配1位字节,浮点型分配4个字节,内存中每一个字节都有一个编号,这个就是“地址”,地址标志内存单元,而内存单元是用来存放数据的。)

内存单元的内存和内存单元的地址的区别:
程序:
int i,j,k;
编译的时候,分配内存:
2000,2001分配给i,
2002,2003分给给j,
2004,2005分配给k;
即为:内存单元的内容就是地址中存放的数据,而地址就是2000~2005等。

在程序中,一般是“通过变量名”来对内存单元进行存取操作的。(程序员对变量以及方法的使用)
实际上,计算机中的实际运行为:计算机编译程序之后,将变量名转化为变量的地址,对变量的存取都是通过地址来进行的。
总结:从程序员的角度可以看到一种别名的方式,从计算机的角度上看是实际的操作。
eg:
printf("%d",i);
(编译的时候会将i这个变量,编译成为一个对应的地址)
找到i变量的地址(2000),从2000开始的两个字节取出数据,然后输出。
scanf("%d",&i);
将键盘中输入的值存放到i对应的地址上(i整形变量的地址为:2000,2001)。

若是:
k = i+ j;
将i(2000,2001)存放的值和j(2002,2003)存放的值进行相加,送到k所占用的内存地址为2004,2005的内存地址上。
这种变量地址存取变量值的方式成为“直接访问”方式。

总结:我们可以回顾一个“微机”课程上的汇编的集中方式。

另一种访问的方式:
简介访问:即为将变量的地址存放在另外一个变量中。
(c语言中的类型变量的定义)c语言中,程序可以定义整形变量、字符变量、实型变量。
同时也是可以定义这样的一个变量的,就是用它来存放地址。
eg:我们定义一个变量t_pointer 用来存放整形的变量地址。它被分配为3010,3011这两个字节,可以通过下面的语句将i的地址(2000)存放在这个变量中。
t_pointer = &i;所以这个时候的t_pointer的值就是2000(即为它的值就是i的变量的地址的起始地址2000);
下面来了解一下简介方式进行对数值进行存储:
先找到i的地址存放的遍历t_pointer,然后从里面获取i的地址(2000),然后懂啊2000,2001里面获取相应的i的值。
这个就是中间多了一个变量。============>(间接存储(地址变量))

总结一下:i的变量
1)、直接方式,就是知道i它的地址,然后直接获取i的值;直接通过i的变量的i的地址量进行对i的值得访问。
2)、将i的变量的地址,存放到另外一个专门是用来存放地址的变量中。所以在访问的时候需要通过存放地址的-变量获取到相应的的地址 ,然后通过地址来获取i值。

(所谓的“指向”,就是存放内存的地址来进行相应的指定,这样就可以通过这个变量来访问它所指向的地址的位置。)
通常:
我们经常会说,通过地址指向能够找到所需要的单元,可以说地址指向待单元变量。
因此:地址形象化为指针。意思即为:通过它能够找到以它为地址的内存单元。(eg:根据地址2000就能够找到变量i的存储单元,从而读取其中的值。)
一个变量的地址称为这个变量的指针。上述:2000是i的指针,t_pointer就是一个指针变量。 指针变量的值就是地址(或者说是:指针)
区分指针变量和指针:
eg:变量i的指针是2000,而不能够说i的指针变量是2000,i的指针变量是t_pointer。明白啥为变量。

3)、指针就是一个地址,而指针变量就是一个存放地址的变量。、

再一次总结:
(1)指针(地址)同意概念,指针变量就是存放地址的变量。

(2)直接存储不存在指针变量的问题,而间接存储需要涉及到变量。


变量的指针和指向变量的指针变量


变量的指针就是变量的地址,存放变量的地址的变量就是指向变量的指针变量。

为了表述指针变量和 它所指向的变量的关系,可以使用“*”来表示。
eg:(*t_pointer )是t_pointer所指向的变量。

i = 3;
*t_pointer = 3; 即为:将3赋值给指针变量t_pointer所指向的变量。

1、定义一个指针变量
(c语言(强类型语言)固定每一个变量在使用之前必须先定义,指定类型,并且按此来分配内存单元)
指针变量定义为指针类型。
eg:
一般的:int i,j;  //定义两个整形变量i,j
指针的: int *t_pointer_1,*t_pointer_2;//定义两个指针变量,
指针类型中:左端的int是在定义指针变量的时候,必须指定的“基本类型”,指针变量的“基本类型”用来规定了指针变量可以指向的变量的类型。上面的两个指针可以指向基本类型为int的,而不能够指向浮点类型的数据。

第一的格式:
基本类型 * 指针变量名;
eg:
float * pointer_3;
char * pointer_4;

指针变量之间的的赋值。
如何使指针指向另外一个变量呢?
eg:
t_pointer_1 = &i;
t_pointer_2 = &j;
所以:将变量i的地址存放在指针变量t_pointer_1中,因此,pointer_1就指向了变量 i;j也是同样。
这个时候*t_pointer_1 就表示是i的值。

定义指针变量的时候注意两点:
(1)指针变量的前面的“ * ”表示该变量的类型为指针型变量。指针变量名是t_pointer_1,而不是(*t_pointer_1),这个和其他的基本类型的定义不同。
(2)定义指针变量的时候,必须指定基本的类型。
原因:不同的基本的类型,指针所指向的位置的移动等等操作是不一样的。
eg:如果指针指向的是“整形变量”,那么使“指针移动一个位置”意味着移动2个字节;使指针+1 意味着地址的值加2个字节。如果指针-指向的是浮点型,那么指针增加的不是2而是4。
同时,指针变量只能够指向一种类型的变量,不能够指向其他类型的变量。
下面的错误的例子:
float a;
int *pointer ;
pointer = &a;(错误的)

总结:
1)、指针变量的定义以及符号“*”的含义。
2)、定义指针变量的时候定义好基本的类型,并且一种类型的指针只能够指向它当前类型的指针,可以联想指针的增减操作。


2、指针变量的引用
两个有关的运算符:
(1)& :取地址运算符
(2)* :指针运算符(或者“简介访问”运算符),取其指向的内容。
eg:&a 为变量a的地址,*p为指针变量p所指向的存储单元的内容(即:p所指向的值)。
eg:如下代码

#include <stdio.h>void main(){    int a,b;    int *pointer_1,*pointer_2;    a = 100;b=10;    pointer_1 = &a;//把变量a地址赋值给pointer_1    pointer_2 = &b;//把变量b的地址赋值给pointer_2    printf("%d,%d \n",a,b);    printf("%d,%d \  n",*pointer_1,*pointer_2);}

结果:
100,10
100,10

说明:
(1)&*pointer的含义是什么?(pointer是指针变量)“&”和“*”两个云算符的优先等级是相同的,但是按照自右边而左边方向结合。因而先进行*pointer,在执行&,相当于&(*pointer)一般是这样写,结果即为:a的地址。
(2)*&a的含义是什么?先进行&a(a为基本的类型),即为a的地址,然后在进行*运算,就是a地址指向的变量a。结果即为:a的值。
即为上面的两个是等价的。
(3)(*pointer)++ 相当于a++,括号是必要的。没有括号为:*pointer++ (++ 和* 是等级是相同的),结合运算是自右向左的。所以相当于*(pointer++)。由于++在pointer的值是改变的,这样pointer不再指向a了。
代码:
#include <stdio.h>void main(){    int *p1,*p2,*p,a,b;    scanf("%d,%d",&a,&b);    p1 = &a; p2 = &b;    if(a<b){    p = p1;    p1 = p2;    p2 = p;    }    printf("a=%d,b=%d \n\n",a,b);    printf("max=%d,min=%d \n",*p1,*p2);}
结果:
5,9  //输入
a=5,b=9   //输出
max=9,min=5

说明:a和b并没有交换,他们依旧保持原值。但是p1和p2的值改变了。p1的开始是&a,后来是&b。p2原来的值是&b,后来的值是&a。
(这个方法不是交换两个整形变量的值,而是交换两个指针变量的值)

总结:
1)、指针变量的使用,注意它的的操作符号。
2)、指针的变量操作的时候,改变的是指针变量中存放的地址。而不会直接去改变它所指向的变量的值,像上面。
除非使用*符号来获取值进行改变。


3、指针变量作为函数的参数

函数的参数不经可以是整型、浮点型、字符型等数据,还可以是指针类型。
所用是:将一个变量的地址传送到另一个函数中。

代码:
#include <stdio.h>void swap(int *p1,int *p2);int 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("%d,%d \n",a,b);    return 0;}
(1)void swap(int *p1,int *p2){    int temp;    temp = *p1;      *p1 = *p2;//这种方式改变该地址指向的变量的值    *p2 = temp;}
结果:
5,6  //输入
6,5  //输出

说明;
实参pointer_1 、pointer_2是指针变量,在函数调用的时候,将实参的变量的值传给形参变量,采取的依然是“值传递”方式,这里的“值传递”中的值是地址值。
虚实结合了之后,p1的值是&a,p2的值是&b。这个时候p1和pointer_1是指向同一个变量a,p2和pointer_2同样指向一个变量b。
swap函数体内,使*p1 和*p2 的值互换。也就是a,b的值交换。函数结束了之后p1,p2 销毁,所以交换了数值。
(注意:这里交换的是a,b的值,而不是p1,p2的值。) 这个改变不是通过形参传回给实参实现的,而是通过形参的地址变量和实参指向同一个变量来实现的。

(2)有问题的代码:
void swap(int *p1,int *p2){    int *temp;    *temp = *p1;    *p1 = *p2;    *p2 = *temp;}
运行结果:
5,9
Segmentation fault (core dumped) 分割故障(核心转储)

原因:*temp是指针变量temp所指向的变量。但temp中并无确定的值(它的值是不可预见的),因此temp所直线的单元也是不可以预见的。(也即是temp里面存放的值是不确定,随时改变,如果*temp存放了值之后,再来取不一定是原来的值)
因此,对*temp赋值有可能给一个存储重要数据的存储单元赋值。这样会破坏系统的正常工作状况。所以,应该讲*p1的值赋值给一个临时变量实现。

(3)
void swap(int x,int y ){    int temp;    temp = x;    x =y;    y = temp;}
这里的结果是不会改变的,因为函数是单向传递值的,这里并没有地址等概念,只是存储的数值的单向传递。即为函数调用结束了之后,就会销毁。

解说一下(1)的原理:用指针变量所谓函数参数,在函数执行的过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值得变化依然保留下来,这样就实现了“通过调用函数使变量的值发生变化,而主函数可以使用这些改变了的值”。

(4)注意不要企图改变指针形参的值而是指针的实参的值改变。
void swap(int *p1, int *p2){    int *p;    p = p1;    p1 = p2;    p2 = p;}
编程者的思想:交换pointer_1 和 pointer_2 的值,是pointer_1指向值大的变量。
设想:
(1》》先是pointer_1指向a,pointer_2指向b,
(2》》调用swap函数,将pointer_1 的值传给p1,pointer_2的值传给p2;
(3》》在swap函数里面,使p1与p2的值交换。
(4》》形参p1,p2将地址传回实参pointer_1,pointer_2,想得到输出:9,5 。
但是,不行的。程序输出的结果还是:5,9;
问题出现在第4步:
c语言中实参变量和形参变量之间的数据传递是单向的“值传递”方式,指针变量作为参数也是要遵循这个原则。
不可能通过调用函数来改变实参指针变量的值,但可以改变实参指针变量所指变量的值,像(1)。

使用函数只能够得到一个返回值,而运用指针变量做参数,可以得到多个变化的值(如:(1)所示)[因为它相当于在另外一个入口进行对同一个变量的值操作]。

总结:
(1)指针变量作为参数,同样是“值传递”,单向传递。不过这里传的是指针的值。
(2)函数只可以返回一个值,而指针作为参数,可以对多个值的改变。是通过指针变量所指向的变量的值的而改变。


总结

(1)知道指针、地址、指针变量等等概念。

(2)指针的定义以及符号的使用

(3)指针作为函数的参数进行传递,可以改变多个值。解决了一个函数只能够返回一个值的作用。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 衣服的铁拉链弯怎么办 去旅行衣服皱了怎么办 衣服抽绳出来了怎么办 裤子的绑带掉了怎么办 网纱裙的边卷了怎么办 堵奶宝宝吸不通怎么办 棉麻裙子掉毛怎么办 10个月宝宝吃手怎么办 婴儿连体衣长了怎么办 冰丝面料变长了怎么办 t恤袖口大了怎么办 长袖t恤袖子长了怎么办 机打的扣子掉了怎么办 四个月宝宝头扁怎么办 鞋子前面穿翘了怎么办 休完产假没人带怎么办 休完产假孩子吃奶怎么办 巴布豆童鞋里面臭了到底怎么办 连体裤有点卡档怎么办 宝宝连体衣扣子掉了怎么办 买衣服被骂了怎么办? 把人车刮了跑了怎么办 打工打不下去了怎么办 白色衣服变粉了怎么办 一量血压就紧张怎么办 一紧张就血压高怎么办 不在上班时间在单位受伤怎么办 生活过得太压抑怎么办 高低床踏板断了怎么办 高低床 孩子摔下来怎么办 小孩子太小高低床爬梯怎么办 辞职后单位不发工资怎么办 买了个上下床搬家怎么办 爸妈不让学日语怎么办 把共享单车弄坏了怎么办 裙子沾到单车油怎么办? 外穿的短裤卷边怎么办 蹬完单车膝盖疼怎么办 夏天骑摩托太热怎么办 半框眼镜线断了怎么办 镜片从镜框脱了怎么办