Autoleaders控制组--C语言指针学习笔记

指针

1.指针与地址

要了解指针是什么,首先要了解什么是地址。
可以这样理解地址:我们把某个物品放在了某个地方,这个地方的位置就是它的地址。这就好比我们的家庭地址,代表我们住的地方的位置。类比来说,计算机把一个变量所代表的数据放在内存里的某个地方,那个地方就有一个对应的地址,那么这样的位置就是指针。
在C语言中,对于每一个设置的变量,这个变量都有他对应的地址,计算机通过地址来访问数据。在C语言中我们用取地址符&来获取某个变量的地址,可以在printf格式中用%p以十六进制来输出地址。

int a=100;
int b=&a;
printf("%p",b);

这里我们定义了两个变量,用变量b来表示变量a的地址,再用printf以%p输出变量a的地址。

注意:&只能对某个变量取地址,如果&右边不是一个变量,就不能运行。比如不能对a++,a–这类不是变量的东西取地址。

2.指针变量

2.1指针变量的定义

指针变量就是保存地址的变量,它的值就是所指变量的地址。
定义指针变量需要使用*来定义

符号*是一个单目运算符,用来访问指针的值(所表示的地址上的变量)
可以做左值也可以做右值


int a=0;
int *p=&a;

这里我们定义了两个变量,其中的*p就是一个指针变量,这就是一个指向变量a的一个指针,
指针变量p的值就是变量a的地址。

这里要注意,这个*可以靠近p,也可以靠近int,也就是说
int* p;与int *p; 的效果是一样的。

另外,指针变量在使用之前一定要定义和赋值,如果没有赋值就就无法运行。而且给指针变量赋的值只能是地址,我们用符号&来获取了变量a的地址,然后把地址赋值给了指针变量,就完成了指针变量的定义。
可以定义不同类型的指针,而且无论指向什么类型,指针的大小都是一样的(因为都是地址),但为了避免用错指针,指向不同类型的指针是不能互相赋值的。

不要随便碰0地址,指针不应该具有0值,但你可以用0地址表示一些特殊含义,比如:
返回的指针是无效的
指针没有被真正初始化(先初始化为0,这样如果指针没有被真正初始化,指针就具有了0值。)
另外,我们可以用NULL表示0地址

2.2指针的类型转换

指针可以强制类型转换。方法与给变量做强制类型转换一样。

int a;
int *p=&a;
void* q=(void*)p;

这里我们虽然改变了指针p的类型,但变量a仍然是int 类型,给指针做强制类型转换并不会改变所指变量的类型。

3.指针的基本用法

3.1指针变量赋值

定义了指针变量之后,就可以通过指针变量来修改所指变量的值了。

int a=0;
int *p=&a;
*p=1;

这里我们借用上次的例子,在定义了变量a时,我们给a了一个初始值0,我们可以通过给*p赋值,来修改变量a的值。(如上,我们给 *p赋值为1,此时a的值也为1了。
类似的,当定义了指针变量之后,使用 *+指针变量 的格式可以修改所指地址的数据。

3.2用于在函数中做参数

当指针变量作为函数参数时,可以在函数里访问函数外的变量。

void fdd(int *a){
	*a=8;
}
int main(){
	int a=0;
	int *p=&a;
	fdd(p);

这里我们定义了一个函数fdd,它的参数是一个指针变量,通过这个指针,我们可以在函数fdd里面访问到函数外面的变量a,这里我们在函数fdd里对指针的值进行了修改,那么函数main中的变量a的值就被修改了。
当函数需要有多个返回值(两个及以上)的时候,就可以使用指针来帮忙了。

void exchange(int *a,int *b){
	int c=*a;
	*a=*b;
	*b=c;

假如我们要定义一个函数用来交换两个变量的值,由于有两个返回值,就要用指针来帮忙了。
这里我们定义了函数exchange,exchange用两个指针变量作为参数,在函数exxhange中通过指针,可以来交换两个变量的值。

4.指针与数组

4.1用指针修改数组内数据

指针也可以指向数组,我们可以通过指针来改写数组里的数据。

int a[100];
int *p=a;
*p=1;

这里我们命名了一个数组a,一个指向a都指针变量p。指针p的初始位置是a[0]。当我们直接使用指针变量p来修改数组a的数据时,实际上修改的是啊a[0]。也就是说,一个数组a与a[0]的地址是同一个地址。

p++;
*p=2;

我们可以直接做p++,也就是指针的自加自减运算,如果做p++,能使指针指向下一位,如果做p–,就可以使指针指向上一位。我们做了p++后,使用指针来赋值时,修改的就是a[1]的数据。

4.2作函数参数的指针与数组

作为函数参数的时候void s(int *a)void s(int a[])是等价的。可以这样去理解,数组变量是特殊的指针,因为,数组变量本身的值就是一个地址(指针),在使用指针变量指向数组是不需要使用取地址符&。(例int a[10]; int *p=a;)

这里注意,虽然数组变量表达的是地址,但数组单元表达的是变量,因此需要使用取地址符&(举例int *p=&a[1]

当然,运算符[]既可以对数组做运算也可以对指针做运算。也就是说int a[10];int *p=a;的时候,p[0]与a[0]是等价的。

如果我们命名的指针变量指向的只是一个变量,而不是数组,我们也可以把指针p看成是一个长度为一的数组。

同理,运算符*既可以对数组做运算,也可以对指针做运算。
我们前面说,数组变量是特殊的指针,是因为数组是一个const的指针,不能对数组赋值。

5.指针与const

5.1指针是const

当指针是const时,表示指针一旦得到了某个变量的地址,就不能再指向其他的变量,即地址已经固定,不能更改了。

int i;
int *const q=&i;//命名了const 的指针

当我们命名了const的指针后,仍然可以通过指针来赋值,但不能做指针的自加自减运算了(因为指针做自加自减运算会改变指针所指的地址)。

5.2所指的是const

这是我们就不能通过指针去修改那个变量的值了,但这并不意味着那个所指的变量就是const。

int i;
const int *p=&i;//命名了所指是const的指针

这里我们命名了所指是const的指针,但我们仍然可以直接给i赋值,比如直接做i=10;
我们也可以修改指针p所指的地址,比如直接做p=&j;

5.3判断const

判断到底是指针不可修改
还是通过指针不可修改,
关键看const与*的位置,

如果const在* 前面,那就是 通过指针不可修改。
如果const在* 后面,就是指针不可修改。

5.4转换

总是可以把一个非const的值转换成const。

void f(const int *p)

这里定义的函数虽然要求要const的指针来作参数,我们也可以直接给他一个不是const的指针。所以这更像是一种保证,在函数f里面保证不会通过指针修改变量的值。

5.5const的数组

数组变量已经是const的指针了,这里const的数组表示数组的每个单元都是const,因此也必须对const的数组进行初始化赋值。。

const int a[]={1,2,3};

因为当数组作为函数参数的时候,传入函数的是地址,所以函数内部可以对函数值进行修改。但如果我们设置参数为const的数组,就可以保护数组的值不被函数破坏。

6.指针的运算

前面我们说过,指针可以通过自加自减运算来改变所指的变量,但如果指针不是指向一片连续分配的空间(比如数组),那这种运算毫无意义。
除此之外,指针与指针之间也可以做相减运算。

int a[10];
int *p=a[0];
int *p1=a[5];
int c=p1-p;

这里我们让指针p1与p相减,得到的值将会是p1与p地址之差,如果将地址之差除以数组a的单元大小,将得到p1与p之间有多少个东西。
当然,还有一种更为常用的指针运算,就是*p++,它可以取出p所指的那个数据来,完事之后顺便将p移到下一个位置去。

这里有两个运算符,其中*的优先级低于++,但对变量p做p++,其所表示的值是p+1之前的值。

7.用指针动态申请内存

动态申请内存需要先引入头文件<stdlib.h>,然后使用函数malloc。

#include <stdlib.h>
int* a=(int*)malloc(n);/*(由于函数malloc
的返回值类型是void*,我们还要做强制类型转换。)*/

free(a);/*使用malloc之后一定要用free函数
将动态申请的内存还回去。*/

使用malloc动态分配内存的时候,是以字节为单位的,也就是说n是多少就动态分配多少字节。当然,如果我们要动态分配内存是n个int(每个int是四个字节)的时候就可以用sizeof来计算。

#include <stdlib.h>
int *a=(int*)malloc(n*sizeof(int));

如果申请失败了,malloc函数将返回0,也就是NULL。
申请的动态内存用完之后要用free()函数将申请的内存还回去,否则能用的内存将变少。

注意:只能还申请空间的首地址。地址变了,就不能直接free。由于0地址是不可用来申请的,free(NULL)不会出错。因此我们可以初始定义指针地址为0,这样一旦用free()返还的时候,直接free(NULL)就好了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值