C语言 为什么不能返回NULL

lymnna71  于 2023-03-07  发布在  其他
关注(0)|答案(4)|浏览(267)

我是一个初学者,正在学习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
但不知道解决办法是什么。

kcrjzv8t

kcrjzv8t1#

如果指针check_NULL等于NULL,则此语句

printf("%s", check_NULL);

调用未定义的行为。
至少你应该写

if ( check_NULL != NULL ) printf("%s", check_NULL);

请注意,以使此语句正确

free(check_NULL)

该函数应当返回空指针或指向动态分配的存储器的指针。
注意这个短语
文本中没有任何内容,
表示传递给函数的是一个空字符串。要检查字符串是否为空,您应该编写如下代码

if ( text[0] == '\0' )
//...

if ( !*text )
//...
shstlldc

shstlldc2#

替代printf()的另一种解决方案:

printf( "%s", check_NULL ? check_NULL : "(null)" );
i34xakig

i34xakig3#

这里的其他答案都很好。本质上,你不能解引用NULL。我也想给出一些直觉。
回想一下,在C语言中,字符串只是内存中的字节序列(代表ASCII字符),我们可以把内存中的任何地方(它本身就是一个长的字节序列)当作字符串,一旦遇到一个值为0的字节(字符'\0'),我们就把该字符串计数为终止。
为了深入理解这一点,让我们看一个strlen实现示例:

int strlen(char *str) {
    int len = -1;
    // will evaluate to 0 (false is just 0 in C) when we reach a null terminator.
    while (str[++len]);

    return len;
}

我们从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),我的高级编程教授称之为"指针的大统一定理"。

ix0qys7i

ix0qys7i4#

你好像想要这样的东西:

char* check_for_NULL(const char *text){
    if(text == NULL){
        return "(null)";
    }
...
}

C语言不像Ruby或者Python,它不会用魔法把NULL指针转换成字符串。
你也在一个非动态分配的指针上调用了free(),你不能显式地释放它们;你只能释放通过malloc()calloc()realloc()分配的东西。像"(null)"这样的字符串永远存在,不能被释放。

相关问题