c - string 没有以 NULL 结尾,但仍然表现正常,为什么?

标签 c string pointers

在下面的代码中,我使用 strncpy() 将一个字符串复制到 char* str,它有 10 个字符长。

现在根据 strncpy() 手册,“警告:如果 src 的前 n 个字节中没有空字节,则放在 dest 中的字符串不会以空终止。”这正是这里发生了什么。

源字符串有 26 个字符长,我复制了 10 个字符,因此在 str 的末尾没有放置空字符。

但是当我打印 str 的内容时,从 0 开始直到我得到 '\0',它表现正常。

为什么?当末尾没有'\0'时,为什么循环会停在正确的位置?

我的理解是它应该给出“段错误”或者至少它不应该停在那里并继续打印一些垃圾值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 10

int main()
{
    char *str ;
    str = malloc( sizeof( char ) * SIZE );
    if( str == NULL ) 
        exit( 1 );
    memset( str, 0, sizeof( char ) * SIZE );

    strncpy( str, "abcdefghijklmnopqrstuvwxyz", sizeof( char ) * SIZE );

    unsigned int index;
    for( index = 0; str[ index ] != '\0' ; index++ ) {
        printf( "str[ %u ] has got : %c \n ", index, str[ index ] );
    }

    return 0;
}

这是输出:

 str[ 0 ] has got : a
 str[ 1 ] has got : b
 str[ 2 ] has got : c
 str[ 3 ] has got : d
 str[ 4 ] has got : e
 str[ 5 ] has got : f
 str[ 6 ] has got : g
 str[ 7 ] has got : h
 str[ 8 ] has got : i
 str[ 9 ] has got : j

我们将不胜感激。

编辑

是否有正确的方法来检查字符串是否以 '\0' 结尾?我一直认为上面的循环是最终的测试,但现在看来不是。

假设我们从其他程序员开发的某个函数中获得了一个字符串。现在我们如何知道它在正确的位置以'\0'结束。可能不是,然后它会超出实际大小,直到我们得到一些 '\0'。我们永远无法知道字符串的实际大小。

那么我们如何应对这种情况呢?

有什么建议吗?

最佳答案

碰巧在分配 block 的末尾之后有一个空字节。

很可能 malloc() 分配更多内存并放置恰好包含空字节的所谓的保护值,或者放置一些元数据供 使用free() 之后,这个元数据恰好在那个位置包含一个空字节。

无论如何,你不应该依赖这种行为。您必须为空字符请求 (malloc()) 多一个字节,以便空字符位置也合法地分配给您。

没有可移植的方法来测试字符串是否正确地以 null 结尾。可能会发生这样的情况,一旦您越过分配 block 的末尾,您的程序就会崩溃。或者可能发生在 block 末尾之外的某处存在空字符,并且您稍后在处理被误解的字符串时覆盖了 block 末尾以外的内存。

理想情况下,您需要一些函数来检查给定地址是否已分配给您并且是否与另一个给定地址(可能是 block 的开头)属于同一分配。这会很慢而且不值得,而且没有标准的方法可以做到这一点。

换句话说,如果您遇到一个本应以 null 结尾但实际上并非如此的字符串,您就大错特错了——您的程序将遇到未定义的行为。

关于c - string 没有以 NULL 结尾,但仍然表现正常,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1464466/

相关文章:

所有编译时优化都可以通过链接时优化来完成吗?

c - 使用来自 C 的系统调用,我如何获得 CPU 的利用率?

java - 如何获取两个特定字符串之间的文本

java - 从字符串中过滤单词

你能在指向数组的指针中打印内容吗?

c - 意外输出打印一个 float 转换为 int

c - 是什么导致了该函数中的段错误?

c - C 中原始类型的位

javascript - String.fromCharCode() 是如何实现的?

c++ - vector 成员被重置且不可访问