简体   繁体   English

"使用 malloc 分配字符串"

[英]Allocating string with malloc

I'm new in programming in C and now I'm studying strings.我是 C 编程新手,现在我正在研究字符串。 My question is: if I allocate a string using malloc (as in the code below), is the NULL character automatically inserted at the end of the string?我的问题是:如果我使用malloc分配一个字符串(如下面的代码),NULL 字符是否会自动插入到字符串的末尾? I find an answer in another question here, and it seems that the NULL character is not automatically included.我在这里的另一个问题中找到了答案,似乎 NULL 字符没有自动包含在内。 But here comes the problem: I know functions like strlen don't work if there isn't the NULL character, and in this code I use it and it works.但是问题来了:我知道如果没有 NULL 字符,像strlen这样的函数就不起作用,在这段代码中我使用它并且它起作用。 So I think there is \\0 at the end of my string, even if I don't write it anywhere.所以我认为我的字符串末尾有\\0 ,即使我没有在任何地方写它。 What's the answer?答案是什么?

Here's the code:这是代码:

#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;
}

malloc() returns a void* pointer to a block of memory stored in the heap. malloc()返回一个void*指针,指向存储在堆中的内存块。 Allocating with malloc() does not initialize any string, only space waiting to be occupied.To add a null-terminating character, you either have to do this yourself, or use a function like scanf() , which adds this character for you. 使用malloc()分配不会初始化任何字符串,只会占用等待占用的空间。要添加空终止字符,您必须自己执行此操作,或使用scanf()类的函数,它会为您添加此字符。 Having said this, you need to allocate space for this \\0 character beforehand. 说完这个之后,你需要事先为这个\\0字符分配空间。

Your malloc() call should be this instead: 你的malloc()调用应该是这样的:

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

Note: You don't need to cast return of malloc. 注意:您不需要转换malloc的返回。 For more information, read this . 有关更多信息,请阅读此内容

Another thing to point out is sizeof(char) is 1 , so multiplying this in your malloc() call is not necessary. 另外要指出的是sizeof(char)1 ,所以在malloc()调用中乘以它是没有必要的。

You also need to check if malloc() returns NULL . 您还需要检查malloc()返回NULL This can be done like this: 这可以这样做:

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

Also, you can only use strlen() on a null-terminated string, otherwise this ends up being undefined behaviour . 此外,您只能在以null结尾的字符串上使用strlen() ,否则最终会出现未定义的行为

Once scanf() is called, and the stringa1 contains some characters, you can call strlen() on it. 一旦调用了scanf() ,并且stringa1包含一些字符,就可以在其上调用strlen()

Additionally, checking return of scanf() is also a good idea. 另外,检查scanf()返回也是一个好主意。 You can check it like this: 你可以这样检查:

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

Your code with these changes: 您的代码包含以下更改:

#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;
}

if I allocate a string using malloc (as in the code below), is the NULL character automatically inserted at the end of the string? 如果我使用malloc分配一个字符串(如下面的代码所示),是否在字符串末尾自动插入NULL字符?

No. malloc() returns a block of uninitialized memory. 不, malloc()返回一块未初始化的内存。

I know functions like 'strlen' don't work if there isn't the NULL character, and in this code I use it and it works. 我知道如果没有NULL字符,'strlen'之类的函数不起作用,并且在这段代码中我使用它并且它有效。 So I think there is '\\0' at the end of my string, even if I don't wrote it nowhere. 所以我认为在我的字符串末尾有'\\ 0',即使我没有在任何地方写它。

scanf() inserts the null byte ( '\\0' ) for you when you use %s format specifier (assuming scanf() succeeded). scanf()插入空字节( '\\0'你)当您使用%s格式说明(假设scanf()成功)。

From man scanf() : 来自man scanf()

s Matches a sequence of non-white-space characters; s匹配一系列非空白字符; the next pointer must be a pointer to the initial element of a character array that is long enough to hold the input sequence and the terminating null byte ('\\0'), which is added automatically. 下一个指针必须是指向字符数组的初始元素的指针,该字符数组的长度足以保存输入序列和终止空字节('\\ 0'),该字节是自动添加的。 The input string stops at white space or at the maximum field width, whichever occurs first. 输入字符串在空白处或最大字段宽度处停止,以先发生者为准。

(emphasis mine). (强调我的)。

By the way, you should do error checking for scanf() and malloc() calls. 顺便说一下,你应该对scanf()malloc()调用进行错误检查。

The definition of "string" in C is a sequence of characters, terminated by a null character . C中“string”的定义是一个字符序列,以空字符结尾

To allocate memory for a string, count the chracters (eg strlen ) and add 1 for this terminating null character. 要为字符串分配内存,请计算chracters(例如strlen )并为此终止空字符添加1。

Functions like scanf and strcpy add the null character; scanfstrcpy等函数添加空字符; a function like strncpy doesn't always do that. strncpy这样的函数并不总能这样做。

malloc returns pointer to an uninitialized memory extent. malloc返回指向未初始化的内存范围的指针。

If you want that the memory extent would be initialized by zeroes then you can use another standard function calloc instead of malloc . 如果你想要用零初始化内存范围,那么你可以使用另一个标准函数calloc而不是malloc

Take into account that usually such a question like this 考虑到通常这样的问题

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

imply that the terminating zero is not counted. 暗示终止零不计算在内。 So you have to allocate one more byte of memory. 所以你必须再分配一个字节的内存。 For example 例如

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

or 要么

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

In the last case you may apply the function strlen which returns 0 because the memory extent is zero-initialized. 在最后一种情况下,您可以应用返回0的函数strlen ,因为内存范围是零初始化的。

This call of scanf 这个scanf调用

scanf("%s", stringa1);

is unsafe. 是不安全的。 It is better to use fgets instead. 最好使用fgets代替。 For example 例如

fgets( stringa1, n + 1, stdin );

This function can append the string with the new line character. 此函数可以使用新行字符附加字符串。 To remove it from the string you can write 要从字符串中删除它,您可以编写

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

The easy way to achieve this is to include cs50 library.实现这一点的简单方法是包含 cs50 库。 Just use get_string function:只需使用 get_string 函数:

#include <stdio.h>
#include <cs50.h>

int main(void) {
    // input the string to stringa1
    char *stringa1 = get_string("Insert the string: ");

    // call the string
    printf("The string you type was: %s\n", stringa1);

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM