提问人:asdfg 提问时间:3/3/2023 最后编辑:asdfg 更新时间:3/4/2023 访问量:102
为什么我不能返回 NULL?
why can't I return NULL?
问:
我是一个初学者,试图在 c 语言中学习动态内存分配。
如果文本中没有任何内容,我尝试返回 NULL,如果它包含某些内容,我想返回文本。
char* check_for_NULL(const char *text){
if(text == NULL){
return NULL;
}
...
}
(程序的其余部分按预期工作)
如果我把 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,但没有任何效果
看到一个类似的帖子:
但没有得到修复是什么。
答:
如果指针等于则此语句check_NULL
NULL
printf("%s", check_NULL);
调用未定义的行为。
至少你应该写
if ( check_NULL != NULL ) printf("%s", check_NULL);
请注意这一点,以使此陈述正确
free(check_NULL)
该函数应返回 null 指针或指向动态分配内存的指针。
注意这句话
文本中没有任何内容,
表示将空字符串传递给函数。要检查字符串是否为空,您应该编写例如
if ( text[0] == '\0' )
//...
或
if ( !*text )
//...
看来你想要这样的东西:
char* check_for_NULL(const char *text){
if(text == NULL){
return "(null)";
}
...
}
C 不像 Ruby 或 Python 或其他什么。它不会通过魔术将 NULL 指针转换为字符串。
您还调用了未动态分配的指针。您不得明确释放这些内容;您只能释放通过 和 分配的内容。字符串文字,如永远存在,无法释放。free()
malloc()
calloc()
realloc()
"(null)"
另一种解决方案可以取代您的:printf()
printf( "%s", check_NULL ? check_NULL : "(null)" );
这里的其他答案都很好。实质上,不能取消引用 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;
}
我们从引用的地址开始,不断迭代内存,直到找到 0 值,每次递增长度。str
请记住,NULL 是 0,因此当您选择将其作为指针传递时,它会引用 address 。#define
0x0
首先,你的函数本质上是说:拿一个指针,如果它的地址是 NULL,则返回 NULL。否则,返回其地址。看看这是无关紧要的吗?该函数只接受一个指针,然后吐出相同的指针。check_for_NULL
text.
现在,您决定传递并打印生成的字符串。 想要将其参数视为字符串,换句话说,将其视为 ,并将开始取消引用该指针的值,直到它读取值为 0 的字节(“null terminator”, char )。这里的问题是这意味着 printf 取消引用的第一个值是在 address ,我们不允许取消引用。NULL
check_for_NULL
%s
char *
'\0'
0x0
了解该地址不是我们使用的有效地址。这就是我们使用指针来表示错误、无效值等的原因。这是理想的垃圾价值,因为它永远不会不是垃圾。0x0
NULL
几个侧面要点:
使用 -g 标志编译程序(对于 gcc,假设这是您正在使用的编译器)以添加调试信息。如果这样做,valgrind 将指向代码行中问题的确切行,这使得调试变得更加容易。
不要 free() 。您在堆指针上使用 free(),而不是堆栈指针。如果你还不明白这一点,只要知道除非指针是由(或任何其他函数)提供给你的,否则它不需要被释放。check_NULL
malloc()
alloc
有趣的小旁观:总是等价于 .我的高级编程教授称其为“指针的大统一定理”。arr[i]
*(arr + i)
评论
check_NULL = char* check_for_NULL(NULL);
不是瓦洛德。你可能想要但是如果你这样做,你必须在你这样做之前检查NULLcheck_NULL = check_for_NULL(NULL);
printf("%s", check_NULL); free(check_NULL);
text[0] == '\0'