目录
1、char** 和const char** 问题:
今天看书看到一个很有意思的问题,不过在看问题之前,首先得知道一个知识:
我们将实参传递给形参的过程,实际上就是将实参的值赋予给形参的过程。所以如果两个类型之间可以互相赋值没有警告,那么这两个类型就可以作为形参和实参。
这个问题从一个程序开始:
程序1:
void func(const char** p2)
{
;
}
int main()
{
char a = 'a';
char* pa = &a;
char** p1=&pa;
func(p1);
return 0;
}
这个问题其实是要我们判断形参实参是否对应,按上面的预备知识,就是转换为判断“ const char** ”、“char**”这两个类型的数据能不能互相赋值。当时我看到这个程序,我第一感觉就是这个程序是有问题的,两个指针类型不相符嘛,一个有const一个没有const,形参实参不对应嘛,很简单。但是当我跑了一下下面这个程序,竟然跑过了,我就感觉很诧异。之前我一直认为只要两个类型不同,就不能赋值。
程序2:
void func(const char* p2)
{
;
}
int main()
{
char a = 'a';
char* pa = &a;
func(pa);
return 0;
}
于是我看回书上对于指针类型对象赋值的解释:
要想赋值合法,必须要满足:
两个操作数都是指向有限定符或者无限定符的相容类型的指针。左边的指针(被赋值)所指向的类型必须具有右边指针所指向类型的全部限定符。
这里的限定符就是const,看完书上的解释,我再看回程序2,char*和const char*分别是指向无限定符和有限定符的char类型指针,不过它们所指向的都是char类型的变量,char类型不是一个指针变量,char类型和和const char 类型是相容的。那为什么说const char * 的指针类型所指向的内容是const char 类型呢?我们来看看下面的一段解释:
const (类型) * ---- 本身并不是一个有限定符的类型,它的类型是一个“指向具有const限定符的对应类型的指针”,const 修饰的不是指针,而是指针指向的值。
这里还有一点值得注意,那就是一个指针变量来说,有const和没有const是两个不同的指针类型。再让我们看会为什么char *和const char *是赋值合法的。因为首先它们指向的数据类型分别是是char和有限定符的char类型,这两种数据类型是相容的,并且左边的指针所指向的类型有右边指针所指向类型的全部限定符(左边有const,右边没有)。满足了可以赋值的合法条件。所以它们是合法的。
这里我们看回程序1:因为程序1中const char ** 所指向的数据类型是“ 有const限定符修饰的char类型的指针” 类型;而char** 所指向的数据类型是 “ 没有const限定符修饰的char类型的指针 ”类型。所以两个指针类型是不同的!所以它们是不相容的。故它们的赋值不合法。
2、NUL和NULL问题:
我们熟知NULL代表的是空指针,即一个不指向任何位置的指针,那么NUL代表什么呢?其实NUL代表的是:字符串的结尾的\0的位模式。
3、sizeof返回值问题:
首先我们来看一个程序:
int main()
{
int a = -1;
if (a > sizeof(int))
printf("hello\n");
return 0;
}
上面的程序会输出吗?乍一看,当然不会,int类型大小是4,4当然大于-1,怎么可能会有输出,但是程序一运行,傻眼了,竟然输出了。那究竟是为什么呢?
其实sizeof的默认返回值是一个无符号的int类型变量,但是这个无符号的类型变量与一个有符号的类型变量a比较时,a会自动算术转换位无符号整型。而-1要是发生无符号整型转换,那将是一个非常大的数字!
4、malloc下的strlen问题:
对于我们用malloc开辟一个字符串,我们要注意不能写成:
malloc(strlen(str));
因为字符串是要有“\0”作为结尾的!!所以要改为 :
malloc(strlen(str)+1);