c语言malloc定义报错core,搞清楚C语言指针

Part 0:为什么要写这篇文章

C语言中的指针是C语言的精髓,也是C语言的重难点之一。

然而,很少有教程能把指针讲的 初学者能听懂 ,还不会引起歧义。

本文章会尝试做到这一点,如有错误,请指出。

Part 1:地址和 &

我们先抛开指针不谈,来讲一个小故事:

一天,小L准备去找小S玩。但是小L不知道小S的家住在哪里,正当他着急的时候,他看到了一个路牌,上面写着:小S的家在神仙小区403

哦,真的是要素过多。为什么这么说?

小L和小S :我们可以看做是两个变量/常量。

小S的家 :这里可以看做是变量/常量小S的地址。

我们要搞清楚,每个变量/常量都和我们一样:我们每个人都有自己的家,正如变量也有自己的地址。 通俗的理解,地址是给变量/常量来存放值的地点 。

路牌 :注意注意注意!这里就指出了变量/常量小S的地址:神仙小区403

事实上,我们等会会讲,输出一个变量的地址其实是个16进制的数字。

搞懂了上面,我们再来聊聊

&

& 这个符号我们一个不陌生,你最初用到应该是在: scanf("%d",&a) 里边。

& 叫做 取址符 ,用来获取一个变量/常量的地址。

那么我们为什么要在 scanf 里边用 & ,不在 printf 里边用呢?

一开始我也很疑惑,后来我看到了这个例子:

你是一个新生,你要进教室。

但是你并不知道教室在哪里,这个时候你需要教室的地址。

下课了,你要出教室。

由于你已经在教室里了,你就不需要获取教室的地址就可以出去了。

Part 2:一定要记住的东西

一定要记住: 指针就是个变量!

重要的事情说三次:

指针就是个变量!他储存的是地址!他自己也有地址!

指针就是个变量!他储存的是地址!他自己也有地址!

指针就是个变量!他储存的是地址!他自己也有地址!

为什么这么说?我们从指针的定义开始:

指针的定义方法: [名称]

也就是说,指针的定义大概是这样的:

int* ip; //类型是int*,名称是ip

float* fp; //类型是float*,名称是fp

double* dp; //类型是double*,名称是dp

有的书上会这么写:

int *ip;

float *fp;

double *dp;

这么写当然没问题,但是对于初学者来说,有两个问题:

有的初学者会把 *p 当做是指针名

有的初学者会把 定义时出现的 *p 和 取值时出现的 *p 弄混

指针他有没有值?有!我们会在下一节给他赋值。

既然他的定义方式和变量一样,他也有值,他为什么不是变量呢?

Part 3:与指针相关的几个符号

与指针相关的符号有两个,一个是 & ,一个是 * 。

先来聊聊 & 。

& 我们上面讲过,他是来取地址的。举个例子:

#include

int main(){

int a = 10;

float b = 10.3;

printf("%p,%p",&a,&b);

}

%p 用来输出地址,当然,你也可以写成 %d 或者 %x 。先不管这个,我们来看看他会输出什么:

39440d38f377295408d526bcc9f12a95.png 那么也就是说,变量

a 和

b 的地址是

000000000062FE1C 和

000000000062FE18

那么我们怎么把这个地址给指针呢?很简单: p = &a; ,举个例子:

#include

int main(){

int a = 10;

int* p;

p = &a;

printf("a的地址:%p\n",&a);

printf("指针p自身的地址:%p\n",&p);

printf("指针p指向的地址:%p",p);

}

得到输出:

a的地址:000000000062FE1C

指针p自身的地址:000000000062FE10

指针p指向的地址:000000000062FE1C

你发现了吗?如果我们有 p = &a; ,我们发现:直接输出p会输出a的地址,输出&p会输出p的地址(这就是为什么我一再强调p是个变量,他有自己的地址,正如路牌上有地址,路牌自身也有个地址一样)。

请注意!如果你的指针为 int* ,那么你只能指向 int 类型;如果是 double* 类型,只能指向 double 类型,以此类推

当然, void* 类型的指针可以转化为任何一种不同的指针类型(如 int* , double* 等等)

那么,我们来聊聊第二个符号 *

* 有两个用法。第一个在定义指针时用到,第二个则是取值,什么意思?看下面这个例子:

#include

int main(){

int a = 10;

int* p;

p = &a;

printf("a的地址:%p\n",&a);

printf("指针p自身的地址:%p\n",&p);

printf("指针p指向的地址:%p\n",p);

printf("指针p指向的地址的值:%d",*p);

}

得到输出:

a的地址:000000000062FE1C

指针p自身的地址:000000000062FE10

指针p指向的地址:000000000062FE1C

指针p指向的地址的值:10

哈,我们得到了a的值!

也就是说,当我们有 p = &a ,我们可以用 *p 得到a的值。

那能不能操作呢?当然可以。

我们可以把 *p 当做a的值,那么,我们尝试如下代码:

#include

int main(){

int a = 10;

int* p;

p = &a;

printf("指针p指向的地址的值:%d\n",*p);

*p = 13;

printf("指针p指向的地址的值:%d\n",*p);

*p += 3;

printf("指针p指向的地址的值:%d\n",*p);

*p -= 3;

printf("指针p指向的地址的值:%d\n",*p);

*p *= 9;

printf("指针p指向的地址的值:%d\n",*p);

*p /= 3;

printf("指针p指向的地址的值:%d\n",*p);

*p %= 3;

printf("指针p指向的地址的值:%d\n",*p);

}

得到输出:

指针p指向的地址的值:10

指针p指向的地址的值:13

指针p指向的地址的值:16

指针p指向的地址的值:13

指针p指向的地址的值:117

指针p指向的地址的值:39

指针p指向的地址的值:0

棒极了!我们可以用指针来操作变量了。

那么,我们要这个干什么用呢?请看下一节:实现交换函数

Part 4:交换函数

交换函数是指针必学的一个东西。一般的交换我们会这么写:

t = a;

a = b;

b = t;

那么我们把它塞到函数里边:

void swap(int a,int b){

int t;

t = a;

a = b;

b = t;

}

好,我们满怀信心的调用他:

#include

void swap(int a,int b){

int t;

t = a;

a = b;

b = t;

}

int main(){

int x = 5,y = 10;

printf("x=%d,y=%d\n",x,y);

swap(x,y);

printf("x=%d,y=%d",x,y);

}

于是乎,你得到了这个输出:

x=5,y=10 x=5,y=10

啊啊啊啊啊啊啊啊,为什么不行!!!

问题就在你的swap函数,我们来看看他们做了些啥:

swap(x,y); --->把x赋值给a,把y赋值给b

///进入函数体

int t; --->定义t

t = a; --->t赋值为a

a = b; --->a赋值为b

b = t; --->b赋值为t

各位同学,函数体内有任何一点谈到了x和y吗?

所谓的交换,交换的到底是a和b,还是x和y?

我相信你这时候你恍然大悟了, 我们一直在交换a和b,并没有操作x和y

那么我们怎么操作?指针!

因为x和y在整个程序中的地址一定是不变的,那么我们通过上一节的指针运算可以得到,我们能够经过指针操作变量的值。

那么,我们改进一下这个函数

void swap(int* a,int* b){

int t;

t = *a;

*a = *b;

*b = t;

}

我们再来试试,然后你就会得到报错信息。

我想,你是这么用的: swap(x,y) 。

问题就在这里,我们看看swap需要怎样的两个变量? int* 和 int* 类型。

怎么办?我告诉你一个小秘密:

任何一个变量加上&,此时就相当于在原本的类型加上了 *

什么意思?也就是说:

int a;

&a ---> int*;

double d;

&d ---> double*;

int* p;

&p ---> int**;//这是个二级指针,也就是说指向指针的指针

那么,我们要这么做: swap(&a,&b) ,把传入的参数 int 换为 int*

再次尝试,得到输出:

x=5,y=10 x=10,y=5

累死了,总算是搞好了

Part 5:char*表示字符串

char*这个神奇的类型可以表示个字符串,举个例子:

#include

int main()

{

char* str;

str = "YOU AK IOI!";

printf("%s",str);

}

请注意:输入和输出字符串的时候,都不能带上 * 和 & 。

你可以用 string.h 中的函数来进行操作

Part 6:野指针

有些同学他会这么写:

int* p;

printf("%p",p);

哦千万不要这么做!

当你没有让p指向某个地方的时候,你还把他用了!这个时候就会产生野指针。

野指针的危害是什么?

第一种是指向不可访问(操作系统不允许访问的敏感地址,譬如内核空间)的地址,结果是触发段错误,这种算是最好的情况了;

第二种是指向一个可用的、而且没什么特别意义的空间(譬如我们曾经使用过但是已经不用的栈空间或堆空间),这时候程序运行不会出错,也不会对当前程序造成损害,这种情况下会掩盖你的程序错误,让你以为程序没问题,其实是有问题的;

第三种情况就是指向了一个可用的空间,而且这个空间其实在程序中正在被使用(譬如说是程序的一个变量x),那么野指针的解引用就会刚好修改这个变量x的值,导致这个变量莫名其妙的被改变,程序出现离奇的错误。一般最终都会导致程序崩溃,或者数据被损害。这种危害是最大的。

不论如何,我们都不希望看到这些发生。

于是,养成好习惯:变量先赋值。

指针你可以这么做: int *p =NULL; 让指针指向空

不论如何,他总算有个值了。

Part 7:总结

本文干货全部在这里了:

指针是个变量,他的类型是 数据类型+* ,他的值是一个地址,他自身也有地址

指针有两个专属运算符: & 和 *

指针可以操作变量,不能操作常量

指针可以表示字符串

请注意野指针的问题

本文没有讲到的:

char[],char ,const char 的区别与联系

const修饰指针会怎么样?

void*指针的运用

多级指针的运用

NULL到底是什么

malloc函数的运用

感谢观看!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值