前言
一个指针变量可以指向计算机任何一块内存,不管该内存有没有被分配,也不管该内存有没有使用权限,只要把该内存地址给它,他就可以指向该内存,C语言没有一种机制来保证指针指向内存的正确性,所以程序员必须提高警惕。
需使用初始化的局部变量
先看一段代码
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)
int main()
{
char *arr;
gets(arr);
printf("%s\n", arr);
system("pause");
return 0;
}
这段程序本没有语法错误,但在vs2013会报错,即arr未初始化,但在有的编译器当中当输入字符串之后,按回车程序直接崩溃,而在Linux表现这段错误(Segment Fault),这是为什么?
未初始化的局部变量的值是不确定的,C语言没有做规定,不同编译器可能有不同结果(所以不要使用没初始化的局部变量),在上例子中arr就是未初始化的局部变量(指针变量也是变量),他的值是未知的,指向哪块内存也不知道,大多数情况这块内存没有被分配,或者没有读写权限。
所以,没有初始化的指针变量初始化为NULL
char *arr = NULL; |
NULL
NULL是“零值”的意思,表示空指针,从表面上理解空指针是不指向任何数据的指针,是无效指针,程序使用不会产生任何效果。(注意区分大小写,null没任何含义)
在上例子中会出现什么效果呢!
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)
int main()
{
char *arr = NULL;
gets(arr);
printf("%s\n", arr);
system("pause");
return 0;
}

运行之后发现还有错,(1)gets()不会让用户输入字符串,也不会向指针指向的内存写入数据;(2)printf()不会读取指针指向的内容,只是给出提示,让用户意识到使用了一个空指针;
实际上很多库函数都会对空指针进行判空:(防止对空指针进行无意义的操作)
(1)
if(psrc == NULL)
return 0;
else
{;}
(2)
//断言,头文件#include<assert.h>
assert(psrc);//或者
assert(psrc!=NULL);
//如果为空,他会报错到具体哪一行
请看下图:
看到其实NULL是一个宏,(void *)0表示把0强制转化为void*类型,最外层()防止发生优先级等问题。所以,NULL指向了地址为0的内存,不是不指向任何输入。
在大多数操作系统中,极小的地址通常不保存数据,也不允许程序访问,NULL可以指向这段地址区间的任何一个地址。
注:(1)C语言并没有规定NULL的指向,只是大部分标准库规定将NULL指向0;
(2)NULL和NUL的区别,NULL表示一个宏定义,空指针,可在代码中使用,NUL表示字符串结束标志'\0',NUL没有在C语言中定义,所以不可以在代码中使用。
void*
void不可以定义变量,因为定义变量前提是要开辟空间,而void是空类型。void*可以定义变量,指针在32位平台占4个byte,但是void*定义的变量不可以解引用。
void用在函数定义当中可以表示函数没有返回值,或者没有形式参数,,而void*表示指针指向的数据的类型是未知的。void*表示一个有效的指针,他确实指向一个实实在在的数据,可是数据的类型尚未确定,在后续的使用过程一般要强制类型转化。
例:
动态内存分配函数malloc(),原型定义如下:
void *malloc( size_t size ); |
malloc()的返回值为void*类型,所以在使用的时候要强制类型转化为需要的类型,请看下例
#include<stdio.h>
#include<stdlib.h>
#pragma warning(disable:4996)
int main()
{
char *arr = (char *)malloc(sizeof(char)*20);//开辟可以保存20个字符的内存大小,返回值转化为char*
gets(arr);
printf("%s\n", arr);
system("pause");
return 0;
}