C语言绝对值得一看的常识讲解:指针篇 篇3

前面的文章对于指针与指针变量、指针变量的定义、指针数组、结构体指针等指针内容进行了讲解,但是指针这部分知识点还是很庞大和细碎的,所以,这里再和大家分享一下指针中值得我们注意的重要知识点。

目录

1.野指针

1.1野指针的成因

1.2如何避免野指针

2.sizeof和strlen的对比

2.1 sizeof

2.2 strlen

2.3 sizeof 和 strlen的对比


1.野指针

概念: 野指针就是指针指向的位置是不可知的、随机的、不正确的、没有明确限制的,换句话说野指针就是其指向有可能很危险的指针。

这种指针如果不加分辨就对其进行操作,有可能引起系统的崩溃,严重地甚至会导致系统死机。

1.1野指针的成因

①指针未初始化

#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
 *p = 20;//指针没有初始化就随意进行操作,有可能导致系统重要数据改变,致使系统崩溃
 return 0;
}

②指针越界访问

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 int *p = &arr[0];
 int i = 0;
 for(i=0; i<=11; i++)
 {
 //当指针指向的范围超出数组arr的范围时,p就是野指针,越界了谁知道指向的是不是重要的存储单元
 *(p++) = i;
 }
 return 0;
}

③指针指向的空间释放

#include <stdio.h>
int* test()
{
 int n = 100;
 return &n;
}
int main()
{
 int*p = test();
 printf("%d\n", *p);
 return 0;
}

上面代码的问题在于看似给指针赋初值了,但事实上函数test建立的变量n在函数运行结束后就自动销毁了,也就是&n指向的空间释放了,所以,实际上指针p指向的空间还是随机的。

1.2如何避免野指针

①指针初始化

如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值为NULL. NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使用的,读写该地址会报错。

#include <stdio.h>
int main()
{
 int num = 10;
 int*p1 = &num;
 int*p2 = NULL;
 
 return 0;
}

比较科学的初始化就是上面代码所呈现的两种。

②小心指针越界

⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。(这种情况比较容易出现在数组的使用中,所以我们要多留意自己建立数组的大小)

③指针变量不再使用时,及时赋值NULL,指针使⽤之前检查有效性

当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使⽤这个指针访问空间的时候,我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问, 同时使⽤指针之前可以判断指针是否为NULL。

④避免返回局部变量的地址

避免③野指针的出现。

⑤注意对于assert的使用

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断⾔”。

assert(p != NULL);

上⾯代码在程序运行到这⼀行语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示。

assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值非零), assert() 不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误流 stderr 中写⼊⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。

2.sizeof和strlen的对比
2.1 sizeof

在之前讲解运算符的时候,我们没有详细讲解sizeof ,在这里和大家讲解一下sizeof。 sizeof 计算变量所占内存内存空间大小的,单位是字节,如果运算对象是类型的话,计算的是使⽤类型创建的变量所占内存空间的大小。

2.2 strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:

size_t strlen ( const char * str );

统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。 strlen 函数会⼀直向后找 \0 字符,直到找到为止,所以可能存在越界查找。

2.3 sizeof 和 strlen的对比

sizeof:

                ① sizeof是操作符

                ② sizeof计算操作数所占内存的大小,单位是字节

                ③ 不关注内存中存放什么数据

strlen:

                ① strlen是库函数,使⽤需要包含头⽂件 string.h

                ②srtlen是求字符串⻓度的,统计的是‘\0’之前字符的隔个数

                ③关注内存中是否有‘\0’,如果没有‘\0’,就会继续往后找,可能会越界

下面是一些很雷同的代码希望,大家认真敲一敲,总结总结,从而加深对于sizeof和strlen的认识及理解,同时能更好地明白两者之间的不同之处。

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

后面两大段代码建议建议对比进行哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值