c语言中认识指针

地址和变量的概念

指针

作用:
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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值