【问题标题】:Allocating string with malloc使用 malloc 分配字符串
【发布时间】:2017-06-09 09:15:59
【问题描述】:

我是 C 编程新手,现在我正在研究字符串。 我的问题是:如果我使用malloc 分配一个字符串(如下面的代码),NULL 字符是否会自动插入到字符串的末尾? 我在这里的另一个问题中找到了答案,似乎 NULL 字符没有自动包含在内。 但是问题来了:我知道如果没有 NULL 字符,像 strlen 这样的函数就不起作用,在这段代码中我使用它并且它起作用。所以我认为我的字符串末尾有\0,即使我没有在任何地方写它。 答案是什么?

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** argv) {
    char *stringa1;
    int n;
    int i;

    printf("How many characters in the string? ");
    scanf("%d", &n);

    stringa1 = (char*) malloc(n*sizeof(char));

    printf("Insert the string: ");
    scanf("%s", stringa1);

    free(stringa1);

    return 0;
}

【问题讨论】:

  • 您的代码对我来说看起来不错。 scanf 将 NUL(非 NULL)放在字符串的末尾。尝试在free(stringa1) 之前拨打strlen
  • 重复@MichaelWalz 所说的内容并挑剔,指针可以是NULL,字符可以是NUL
  • 在以前的版本中我尝试过,它返回我在第一个 scanf() 中输入的数字。
  • 除了casting the result of malloc 之外,我认为您的代码没有真正的问题。它在这里没有特别的负面影响,但被认为是不好的做法,可以隐藏错误。
  • 没有NULL 字符。 NULL 是一个带有 空指针常量 的宏,有些不同。而且C没有字符串类型。

标签: c string malloc


【解决方案1】:

malloc() 返回一个void* 指向堆中存储的内存块的指针。使用malloc() 进行分配不会初始化任何字符串,只有等待被占用的空间。要添加空终止字符,您要么必须自己执行此操作,要么使用像scanf() 这样的函数,它会为您添加此字符。话虽如此,您需要事先为这个\0 字符分配空间。

您的malloc() 电话应该是这样的:

stringa1 = (char*) malloc((n+1)*sizeof(char)); /*+1 for '\0' character */

注意:你不需要强制返回 malloc。欲了解更多信息,请阅读this

要指出的另一件事是sizeof(char)1,因此在您的malloc() 调用中将其相乘是不必要的。

您还需要检查malloc() 是否返回NULL。可以这样做:

if (stringa1 == NULL) {
    /* handle exit */

此外,您只能在以 null 结尾的字符串上使用 strlen(),否则最终会是 undefined behaviour

一旦调用scanf(),并且stringa1包含一些字符,你可以调用strlen()就可以了。

此外,检查scanf() 的返回也是一个好主意。你可以这样检查:

if (scanf("%d", &n) != 1) {
    /* handle exit */

您的代码进行了这些更改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    char *stringa1 = NULL;
    size_t n, slen;

    printf("How many characters in the string? ");
    if (scanf("%zu", &n) != 1) {
        printf("Invalid input\n");
        exit(EXIT_FAILURE);
    }

    stringa1 = malloc(n+1);
    if (stringa1 == NULL) {
        printf("Cannot allocate %zu bytes for string\n", n+1);
        exit(EXIT_FAILURE);
    }

    printf("Insert the string: ");
    scanf("%s", stringa1);

    slen = strlen(stringa1);
    printf("String: %s Length: %zu\n", stringa1, slen);

    free(stringa1);
    stringa1 = NULL;

    return 0;
}

【讨论】:

    【解决方案2】:

    如果我使用 malloc 分配一个字符串(如下面的代码),NULL 字符是否会自动插入到字符串的末尾?

    没有。 malloc() 返回一块未初始化的内存。

    我知道如果没有 NULL 字符,像“strlen”这样的函数就不起作用,在这段代码中我使用它并且它起作用。所以我认为我的字符串末尾有 '\0',即使我没有在任何地方写它。

    scanf() 在您使用%s 格式说明符时为您插入空字节('\0')(假设scanf() 成功)。

    来自man scanf()

    s 匹配一系列非空白字符;下一个 指针必须是指向 a 的初始元素的指针 长度足以容纳输入序列的字符数组 和终止的空字节('\0'),它被添加 输入字符串在空白处或在 最大字段宽度,以先到者为准。

    (强调我的)。

    顺便说一句,您应该对scanf()malloc() 调用进行错误检查。

    【讨论】:

    • 他还应该确保在他的分配中包含用于尾随空字节的空间,并且他应该防止作为程序输入的实际字符串比承诺的长。
    • 谢谢,但是当你谈到scanf()malloc() 的错误检查时我无法理解...
    • @FranzGoogle scanf() 返回扫描成功的项目数;否则,它失败了。 malloc() 如果分配内存失败,则返回 NULL。所以,我的意思是你必须检查这些函数的返回码以检查它们是否失败。如:if (scanf("%d", &amp;n) != 1) { /* failure */}stringa1 = (char*) malloc(n*sizeof(char)); if (stringa1 == NULL) { /* failure */}
    • @P.P.好的。我该怎么做?抱歉,但我是初学者...我可以通过strlen() 进行检查吗?
    • @FranzGoogle 查看我之前关于如何操作的评论的结尾。不确定strlen() 的相关性如何。 strlen() 只返回字符串的长度(并且strlen() 需要一个以空字节结尾的字符串作为输入)。所以,如果malloc() 失败,那么你不能在stringa1 上调用strlen()。您应该只检查每个功能是否失败。
    【解决方案3】:

    malloc 返回指向未初始化内存范围的指针。

    如果您希望将内存范围初始化为零,那么您可以使用另一个标准函数 calloc 而不是 malloc

    考虑到通常这样的问题

    printf("How many characters in the string? ");
    

    表示不计算终止零。所以你必须再分配一个字节的内存。例如

    stringa1 = ( char* )malloc( ( n + 1 ) *sizeof( char ) );
    

    stringa1 = ( char* )calloc( n + 1, sizeof( char ) );
    

    在最后一种情况下,您可以应用返回 0 的函数 strlen,因为内存范围是零初始化的。

    scanf的这个电话

    scanf("%s", stringa1);
    

    不安全。最好改用fgets。例如

    fgets( stringa1, n + 1, stdin );
    

    这个函数可以在字符串后面加上换行符。要从字符串中删除它,您可以编写

    stringa1[strcspn( stringa1, "\n" )] = '\0';
    

    【讨论】:

    • n+1 是从哪里来的?
    • @gumuruh n 是函数 strlen 返回的值。
    【解决方案4】:

    C 中“字符串”的定义是以空字符结尾的字符序列

    要为字符串分配内存,请计算字符数(例如strlen)并为该终止空字符加 1。

    scanfstrcpy 等函数添加空字符;像strncpy 这样的函数并不总是这样做。

    【讨论】:

      猜你喜欢
      • 2021-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多