我是一个初学者,正在学习c中的动态内存分配。
如果文本中没有任何内容,我就返回NULL,如果有内容,我就返回文本。
char* check_for_NULL(const char *text){
if(text == NULL){
return NULL;
}
...
}
(the程序的其余部分按预期工作)
如果我在调用它的地方输入NULL:
int main(){
char *check_NULL;
check_NULL = check_for_NULL(NULL);
printf("%s", check_NULL);
free(check_NULL);
}
我得到的是分段错误而不是null。
当我在valgrind中运行时,我得到了这样的结果:
Invalid read of size 1
Address 0x0 is not stack'd malloc'd or (recently) free'd
我尝试使用calloc为NULL腾出空间,尝试用0代替NULL,但没有任何效果
看到一个类似的帖子:
Valgrind: Invalid read of size 1
但不知道解决办法是什么。
4条答案
按热度按时间kcrjzv8t1#
如果指针
check_NULL
等于NULL
,则此语句调用未定义的行为。
至少你应该写
请注意,以使此语句正确
该函数应当返回空指针或指向动态分配的存储器的指针。
注意这个短语
文本中没有任何内容,
表示传递给函数的是一个空字符串。要检查字符串是否为空,您应该编写如下代码
或
shstlldc2#
替代
printf()
的另一种解决方案:i34xakig3#
这里的其他答案都很好。本质上,你不能解引用NULL。我也想给出一些直觉。
回想一下,在C语言中,字符串只是内存中的字节序列(代表ASCII字符),我们可以把内存中的任何地方(它本身就是一个长的字节序列)当作字符串,一旦遇到一个值为0的字节(字符
'\0'
),我们就把该字符串计数为终止。为了深入理解这一点,让我们看一个
strlen
实现示例:我们从
str
引用的地址开始,不断迭代内存,直到找到一个0值,每次都递增长度。记住NULL是
#define
的0,所以当你选择把它作为指针传递时,它引用地址0x0
。首先,函数
check_for_NULL
实际上是说:取一个指针,如果它的地址是NULL,返回NULL,否则返回它的地址,看到这是多么的多余了吗?,这个函数只是取一个指针,然后把同样的指针吐出来。现在,您决定将
NULL
传递给check_for_NULL
并打印结果字符串。%s
希望将其参数视为字符串,换句话说,视为char *
,并将开始从该指针解引用值,直到读取到值为0的字节("null terminator",char'\0'
).这里的问题是,这意味着printf解引用的第一个值位于地址0x0
,我们不允许解引用它.要知道地址
0x0
对于我们来说不是一个有效的地址,这就是我们使用NULL
指针来表示错误、无效值等的原因。它是理想的垃圾值,因为它永远不会不是垃圾。有几个观点:
用-g标志编译你的程序(对于gcc,假设你使用的是编译器)来添加调试信息,如果你这样做了,valgrind会准确地指向问题所在的代码行,这会使调试变得更容易。
不要使用free()
check_NULL
。free()用于堆指针,而不是堆栈指针。如果你还不明白这一点,只需知道除非malloc()
(或任何其他alloc
函数)提供了指针,否则它不需要被释放。有趣的小旁注:
arr[i]
总是等价于*(arr + i)
,我的高级编程教授称之为"指针的大统一定理"。ix0qys7i4#
你好像想要这样的东西:
C语言不像Ruby或者Python,它不会用魔法把NULL指针转换成字符串。
你也在一个非动态分配的指针上调用了
free()
,你不能显式地释放它们;你只能释放通过malloc()
,calloc()
和realloc()
分配的东西。像"(null)"
这样的字符串永远存在,不能被释放。