这篇文章涉及到空指针常量,结合空指针和野指针一起看。
最近在XCode下编程,遇到一个问题。平时我们判断C语言类型的字符串是否为空,如下
char *p;
...
if(p == "")
...
但是会提示警告:Result of comparison against a string literal is unspecified (use strncmp instead)。当时我就愣住了,因为以前没有特别注意,但是为什么会有警告?(虽然没有错误,但是运行就会发现有问题)
可能会跟编译器有关系。然后我在Cygwin编译器和linux系统gcc编译器编译都没有问题。所以判断是跟编译器有关系。
但是真的是只是和编译器有关系吗?
其实,p == "",是比较是指针所指向的地址是否相等,除非p在比较之前,有p = ""这个语句赋值,不然p 是不可能等于""这个的。详细请看第(4)步。
由此,进一步深究。
(1)不同的编译器和环境,局部变量有的会初始化(Cygwin),有的不会(gcc,但是会指向一个不确定的值)。所以
char* p;
printf("%p\n",p);
printf("%p\n",&p);
printf(">>>%s\n",p);
Cygwin中: 等同于 char* p = NULL。
0x0
0xXXXXXXXX
>>>(null)
gcc:等同于 char *p; p指向了一个不确定的地址。
0xYYYYYYYY
0xXXXXXXXX
(可能是乱码或者空)
注意:全局变量如果没有初始化,编译器都会初始化。
(2)在gcc编译器中,将上述代码改成下面
char* p=NULL;
printf("%p\n",p);
printf("%p\n",&p);
printf(">>>%s\n",p);
结果和Cygwin表现“一样”,当然地址肯定不一样。
再将上述代码修改成:
char* p=NULL;
printf("%p\n",p);
printf("%p\n",&p);
printf(">>>%s\n",p);
if(strlen(p) == 0)
return -1;
运行,则运行到strlen函数出现段错误。
在不同的系统中,NULL并非总是和0等同,NULL仅仅代表空值(参考空指针和野指针),也就是指向一个不被使用的空地址(在大多数系统中,都将0作为不被使用的地址)。在没有将p指向别的有效地址前,判断p是否为空只能if(p == NULL),不能使用 strlen(p)==0等函数,不然会段错误。标准做法是:
if(p != NULL){
if(strlen(p) == 0)
printf("empty");
}
注意:
如果是字符串指针,首先要判断指针是否为空(这个很重要,请看上面出现段错误),否则容易造成段错误。
养成良好变成习惯,定义变量后首先要初始化。
(3)NULL与“”区别
空字符串是“”,会创建一个对象,内容是“”,有内存空间
而NULL,不会创建对象,没有内存
(4)那么如何比较字符串是否相等?
先看下面这个程序:
char *p = (char *)"111";
if(p == "111")
cout << "== Equal" <<endl;
编译和执行都正确。也能正确表示两个字符串是否相等。
再看:
char p[] = {'1','1','1','\0'};
if(p == "111")
cout << "== Equal" <<endl; //不执行
if(strcmp(p,"111") == 0)
cout << "strcmp Equal" <<endl; //执行
为什么p == "111"不相等,但是使用比较函数strcmp比较却是相等?
原因是前者,只是比较 p指针指向的地址 是否等于 "111"字符串的首地址(明显"111"是文字常量区的数据,p是指向栈区的数据地址,所以肯定不一样)
后者只是比较字符串内容是否相等,显然内容是一样的。