C语言指针进阶课程,C语言进阶课程笔记之指针

指针

指针就是保存地址的变量,想一下,无论什么类型的指针,因为地址的所占用的空间是一样的,所以指针所占用的字节应该是一样的。后面不妨给出验证。我们常用的写法无外乎向下面这样

int i;

int* p = &i;

int* p,q;

int *p,q;

指针变量

普通变量的值是实际的值

指针变量的值是具有实际值的变量的地址

a02213c579cc

Paste_Image.png

我们这里不妨就验证一下指针所占的空间到底是不是一样的。

#include

int main(){

char* p = NULL;

int* q = NULL;

int i = 5;

char c = 6;

q =&i;

p =&c;

printf("p's size is %d\n",sizeof(p));

printf("q's size is %d\n",sizeof(q));

return 0;

}

我们在cpp.sh上编译运行的结果是

a02213c579cc

Paste_Image.png

而在我的电脑上运行的结果是

a02213c579cc

Paste_Image.png

对呀,同样的代码,为什么有不同的结果呢?因为我们的运行环境不一样,在我电脑中指针只占用4的字节,而在cpp.sh服务器上每个指针占用8的字节。但是我们要强调的重点是我们char类型的指针和int类型的指针占用 的字节数在同一机器架构下是一样的,也就验证了我们刚刚所言。

作为参数的指针

void f(int* p);//在调用的时候得到某个变量的地址

int i=0;

f(&i);//在函数里面可以通过这个指针访问外面的变量i

访问对应地址中的元素

*是弹幕运算符,用来访问指针所指地址上的变量

可以作为右值也可以作为左值

int k = *p;

*p = k+1;

指针的应用场景

场景一

交换两个变量的值

我们都写过交换两个变量的swap函数,但是当我们从形参传进来两个值的时候,我们能在函数内交换,但是一旦离开了函数,原本的变量根本没有变化,因而我们要传入地址进来

void swap(int *pa, int *pb){

int temp =*pa;

*pa = *pb;

*pb = temp;

}

这样我们就能交换两个变量的值了

场景二

函数要同时返回多个值

一般情况我我们通过函数的return语句返回值的时候只能返回一个,但是如果我们要同时返回多个值该怎么办呢?这时候我们通过参数传入地址,然后通过指针把要返回的值带回到函数外。举个例子:我们写个函数求数组中的最大最下值。

#include

void maxmin(int a[], int len, int *max, int *min){

*max = a[0];

*min = a[0];

for (int i = 0; i < len; i++){

if (*max < a[i])

*max = a[i];

if (*min>a[i])

*min = a[i];

}

}

int main(){

int num[] = { 1, 10, 5, 8, 9, 6, 7, 25, 6, 3, 4 };

int max;

int min;

maxmin(num,sizeof(num)/sizeof(int), &max, &min);

printf("max = %d\n", max);

printf("min = %d\n", min);

return 0;

}

a02213c579cc

Paste_Image.png

在maxmin函数中,我们返回值类型是void,也就是不通过return返回值,但是我们确实得到了max和min,如何做到的?那就是我们穿进去两个地址,在函数内部把地址上的内容改了,所以函数结束以后,我们能得到我们想要的。我们在进一步探索一下,maxmin函数的参数列表中除了我们要传入的数组int a[], 两个指针变量int *max和int *min,还多了一个长度int len 为什么我们不在函数内部做sizeof(a)/sizeof(int) 来得到数组的长度呢?

我们来看一个例子

a02213c579cc

Paste_Image.png

为什么我们的数组才占了4个字节呢?显然,此时a并不表示数组了,那么我们传进来的到底是什么呢?4个字节刚好是一个指针所占用的字节数,没错此时的a就是一个指针。那么我们能否像操作指针一样操作a呢?我们来试一下:

a02213c579cc

Paste_Image.png

没错我们可以像操作指针一样操作a,所以a其实就是一个指针,所以我们在函数内部是不能通过sizeof(a)/sizeof(int)来求得数组的个数的,那么我们只能再传进来一个参数len。

指针最常见的错误

定义了指针变量,还没有指向任何变量就开始使用指针

当你定义了一个指针变量的时候,由于没有指向任何变量,所以它里面的内容是杂乱无章的,可能是个可以访问的地址,也可能是不可访问的地址,无论哪种都不是我们想要的。

a02213c579cc

Paste_Image.png

vs提示我们是使用了未初始化的变量,所以连编译都过不去

a02213c579cc

Paste_Image.png

我们在cpp.sh上运行了一下,通过了,能正常运行,但这不总是那么幸运,万一我们的p内的地址是0,这个特殊的地址,我们的程序就会崩掉。

a02213c579cc

Paste_Image.png

我们把p的值改为了0,程序一直得不到结果,在vs下呢

a02213c579cc

Paste_Image.png

一样的结果,因为我们的0地址是无法访问的。

一般我们用NULL来表示0地址。

指针与const

在使用指针的时候我们经常会看到const,一脸懵逼,你能正确分辨下面的几种写法么?

int i;

int *const p1=&i;

const int *p2=&i;

int const *p3=&i;

三种写法有两种意思,const在*之前,表示指针是const,也就是说指针只能指向这个变量,不能改变,所以一般声明和初始化一起。const在*之后表示不能通过该指针来改变变量的值,并不是说变量不可改变,或者指针不可改变,而是通过该指针改变该变量的值是不允许的。

强制类型转换

void* 这种类型的指针,表示某个地址,但是不明确指出所存储是数据类型。一般用在比较底层的操作中,例如动态分配内存的时候,我们只要告诉系统,请求分配多少字节的内存,并不需要告诉它用来存什么数据 ,所以malloc返回值类型为void*

必要的时候我们可以通过强制类型转换来改变指针的类型

void* p = malloc(128);

int * q = (int*) p;

malloc动态分配内存

有时候我们不知道数组的大小,要传入一个变量n到数组中,在C99之前是不允许的,这时候就要动态分配内存了

具体做法

a02213c579cc

Paste_Image.png

记住不仅仅如此,我们借了内存,还要还回去,不然,有借无还,最终内存会用光的。我们用free函数还回内存

a02213c579cc

Paste_Image.png

指针的运算

指针是地址,地址是可以运算的,有加减运算,比较运算,

那么指针加一是否是地址加一呢?

不是的,指针加一,表示指向下一个单元,如果是int*类型的指针,指针加一,则地址加4,如果是char*类型的指针,指针加一,则地址加一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值