【问题标题】:string dynamic allocation in CC中的字符串动态分配
【发布时间】:2020-10-09 21:56:44
【问题描述】:

我正在编写一个函数,需要:

  1. 从用户那里得到一个完整的句子

  2. 为每个单词动态分配一个可以包含它的内存块

  3. 复制到它里面,并将地址保存到*words指针数组中

我写了一个循环,在每次迭代中从用户插入的句子中获取一个单词,但我不能正确地动态分配它。 这就是我所拥有的:

char str[50];
while(scanf("%s", str) != EOF)
{
    int len = strlen(str);
    char *words = (char*) malloc((len+1)*sizeof(char));
}

我还需要确保:

  • 如果函数成功,则返回输入的单词数。

  • 如果内存分配失败,函数返回-1。

【问题讨论】:

  • 每个循环都会覆盖words 的前一个值,无论如何都会在循环结束时超出范围。在循环之前,您需要一个指针数组和一个索引变量来访问该数组(并为以后计算元素)。您没有问题 (3) 中提到的那个数组。
  • "Get a full sentence from the user" - 您正在无限循环地从用户那里读取单词(除非用户在标准输入中输入 EOF,否则它是无限的,这在大多数平台上都需要特殊的组合键)。你不想读到句末吗?

标签: c string dynamic malloc allocation


【解决方案1】:

条件while(scanf("%s", str) != EOF) 是一个潜在的无限循环,只有在您通过命令行向程序输入EOF 信号时才会停止。

对于包含所有单词的单个字符串,您需要在每次读取时重新分配内存以增加保存字符串的内存空间。

你可以这样做:

Live demo

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

int ret_words(char **words) { //double pointer argument
    char str[50];
    char *temp = malloc(1); //first allocation required
    int count = 0;

    if(temp == NULL){       //allocation error
        return -1;
    }
    do{
        temp = realloc(temp, strlen(str) + strlen(temp) + 2); //reallocate space on
                                                              //each iteration
        if(temp == NULL){                                      
            return -1;
        }
        count++; //count words
    } while (scanf("%49s", str) == 1 && strcat(temp, str) //scan str and append to temp
      && getchar() != '\n' && strcat(temp, " "));         //with spaces between

    *words = temp; //assign temp to words
    return count; //return word count
}
int main() {

    int ret;
    char *words; //pointer to the array of strings
    puts("Enter the string");
    putchar('>');
    ret = ret_words(&words); //returned number of words on success, -1 on error

    printf("Inputed string: %s\nNumber of words: %d", words, ret); //test print
}

约束:在最后一个输入的单词之后不能有任何空格来结束循环。

现在,如果您想要二维数组结构,不仅为单词本身动态分配,还为指向这些字符串的指针动态分配,您将需要一些更特殊的东西,一个三重指针。

将其视为指向字符串数组的指针,这是您需要作为函数参数的内容,以便使调用函数(在本例中为 main 函数)中的更改永久化。

Live demo

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

int ret_words(char ***words) { //triple pointer argument
    char str[50];
    int count = 0;
    char **temp = malloc(sizeof *temp); //allocate a pointer to pointer to char

    if(temp == NULL){       //allocation error
        return -1;
    }
    do {
        temp = realloc(temp, (count + 1) * sizeof *temp); //reallocate space at every scan
        if(temp == NULL){
            return -1;
        } 
        temp[count] = malloc(strlen(str) + 1);
        count++;
    } while (scanf("%49s",temp[count - 1]) == 1 //scan str and append to temp
      && getchar() != '\n');                    //with spaces between

    *words = temp; //assing the allocated array of pointer to the argument
    return count; //return word count
}
int main()
{ 
    char **words; // pointer to pointer to navigate the array of strings

    int ret;
    puts("Enter the string");
    putchar('>');
    ret = ret_words(&words); //returned number of words on success, -1 on error

    for(int i = 0; i < ret; i++) //print each stored one word string
        printf("Word %d: %s\n",i + 1, words[i]);

    printf("Word count: %d", ret); //print the number of words
}

约束:在最后一个输入的单词之后不能有任何空格来结束循环。

请注意,由于这些分配是通过函数的参数进行的,因此存在额外的间接级别,如果它们要在适当的位置使用或由函数返回,您只需要一个简单的指针,在第一个样本,第二个样本中有一个双指针。

【讨论】:

  • 问题指出“(2)为每个字动态分配一个可以包含它的内存块”。但是,在您的回答中,您为 all 单词分配了一个大内存块。尽管这个问题没有明确说明每个单词都应该有自己的“malloc 内存块”,但给每个单词自己的这样的块似乎更明显。这还具有realloc 不必多次复制整个内存缓冲区的优点。但是,我仍然赞成您的回答,因为一个内存块可以被视为包含每个单词的子块。
  • @AndreasWenzel,我没想到,这似乎是一个更正确的解释。我想我必须为它添加一个解决方案。感谢您的支持。
【解决方案2】:

假设您的代码片段中已经嵌入了以下限制:

  • 最大字长为49字节,
  • 用户在句子结束后发出文件结束信号。

这是一个构造指针数组的简单函数:

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

struct context {
    char **array;
    int count;
};

int read_sentence(struct context *cp) {
    char buf[50];

    cp->array = NULL;
    cp->count = 0;

    while (scanf("%49s", buf) == 1) {
        // another word was read
        char **new_array = realloc(cp->array, (cp->count + 1) * sizeof(*new_array));
        char *p = strdup(buf);
        if (new_array == NULL || p == NULL) {
            // allocation error: free previously allocated memory and return -1
            free(p);
            if (new_array != NULL) {
                cp->array = new_array;
            }
            while (cp->count > 0) {
                free(cp->array[--cp->count]);
            }
            free(cp->array);
            cp->array = NULL;
            return -1;
        }
        cp->array = new_array;
        cp->array[cp->count++] = p;
    }
    return cp->count;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    • 2018-01-29
    • 1970-01-01
    • 2015-07-14
    • 2011-10-21
    • 1970-01-01
    相关资源
    最近更新 更多