Выделение памяти для строки в C с помощью malloc - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь выделить память для массива строк, используя malloc. Размер каждой строки неизвестен до ввода от пользователя, поэтому я попытался выделить память для каждого элемента в массиве.

У меня есть некоторые ошибки с кодом, но я не могу их понять или не могу их понять. Я получаю сообщение об ошибке при распределении. Может кто-нибудь сказать мне, что случилось по этому поводу?

bool read_strings(char * strings[], int n) 
{
    int i = 0;
    while (i<n)
    {
        char string[MAX_LENGTH];
        if (scanf("%s", string)!=1)
            return false;
        char* memory= (char*)malloc(sizeof(char)*strlen(string));
        if (memory == NULL)
            return false;
        memory = string;
        strings[i] = memory;
        i++;
    }
    return true;
}

Большое спасибо!

Ответы [ 5 ]

0 голосов
/ 08 января 2019

Чтобы иметь действительно неограниченный буфер в C (или ограниченный объемом памяти и size_t), вы можете постепенно увеличивать выделение памяти.

#include <stdlib.h>  /* realloc free */
#include <stdio.h>   /* stdin fgets printf */
#include <string.h>  /* strcpy */
#include <assert.h>  /* assert */
#include <stdint.h>  /* C99 SIZE_MAX */
#include <stdbool.h> /* C99 bool */

/* Returns an entire line or a null pointer, in which case eof or errno may be
 set. If not-null, it must be freed. */
static char *line(void) {
    char temp[1024] = "", *str = 0, *str_new;
    size_t temp_len, str_len = 0;
    while(fgets(temp, sizeof temp, stdin)) {
        /* Count the chars in temp. */
        temp_len = strlen(temp);
        assert(temp_len > 0 && temp_len < sizeof temp);
        /* Allocate bigger buffer. */
        if(!(str_new = realloc(str, str_len + temp_len + 1)))
            { free(str); return 0; }
        str = str_new;
        /* Copy the chars into str. */
        strcpy(str + str_len, temp);
        assert(str_len < SIZE_MAX - temp_len); /* SIZE_MAX >= 65535 */
        str_len += temp_len;
        /* If on end of line. */
        if(temp_len < sizeof temp - 1 || str[str_len - 1] == '\n') break;
    }
    return str;
}

static bool read_strings(char * strings[], int n) {
    char *a;
    int i = 0;
    while(i < n) {
        if(!(a = line())) return false;
        strings[i++] = a;
    }
    return true;
}

int main(void) {
    char *strings[4] = { 0 }; /* C99 */
    size_t i;
    bool success = false;
    do {
        if(!read_strings(strings, sizeof strings / sizeof *strings)) break;
        for(i = 0; i < sizeof strings / sizeof *strings; i++)
            printf("%lu: <%s>\n", (unsigned long)i, strings[i]);
        success = true;
    } while(0); {
        for(i = 0; i < sizeof strings / sizeof *strings; i++)
            free(strings[i]);
    }
    return success ? EXIT_SUCCESS : (perror("stdin"), EXIT_FAILURE);
}

Я думаю, это правильно. Однако это должно привести к паузе; что если они никогда не нажмут "войти"? Если у вас есть MAX_LENGTH, рассмотрите возможность статического распределения, в зависимости от вашей ситуации.

Редактировать: Время работы в худшем случае также может быть нежелательным; если вводите действительно произвольно большие линии, используйте геометрическую прогрессию для выделения места.

0 голосов
/ 07 января 2019

Я думаю, это то, что вы хотели сделать:

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

int read_strings(char * strings[], int n)
{
    int i = 0;
    char buffer[256] ={0}; /*a temp buffer of fixed max size for input */
    if(NULL == strings)
    {
        return 0 ;
    }

    for (i= 0; i<n; ++i)
    {
      if (fgets(buffer, 256,stdin)== NULL) /*safer then scanf - read input into the buffer*/
        return 0;
        strings[i]= malloc(sizeof(char)*(strlen(buffer)+1)); /* the char poiner in he i place will now point to the newly allocated memory*/
        strcpy(strings[i], buffer); /*copy the new string into the allocated memory now string[i] is pointing to a string*/
    }

return 1;
}
static void printStringsArray(const char* strArr[], size_t size)
{
    int i = 0;
    if(NULL == strArr)
    {
        return;
    }
    for(i = 0; i< size; ++i)
    {
        printf("%s", strArr[i]);
    }

}

 int main(void)
 {
    char * arr[3]; /*array of (char*) each will point to a string after sending it to the function */
    read_strings(arr,3);

    printStringsArray(arr,3);
    return 0;
 }
0 голосов
/ 07 января 2019

По крайней мере, вы должны заменить

char* memory= (char*)malloc(sizeof(char)*strlen(string));
if (memory == NULL)
    return false;
memory = string;
strings[i] = memory;

от

strings[i] = strdup(string)

Обратите внимание, что при использовании scanf("%s", string) разделителем между прочитанной строкой является пробел

0 голосов
/ 07 января 2019

Проблема здесь:

char* memory = (char*)malloc(sizeof(char)*strlen(string));
memory = string; <<<
strings[i] = memory;

Вы потеряете память, если назначите строки указателям, подобным этому.

Или:

a) Скопируйте строку во вновь выделенную память, используя strcpy () или strncpy (), также убедитесь, что у вас достаточно места для символа NULL \0

strings[i] = (char*)malloc(sizeof(char) * (strlen(string) + 1));
strcpy(strings[i], string);

b) Используйте strdup (), который похож на смесь strcpy () и malloc (), он создает достаточно места для вашей строки и копирует ее в новую область памяти

 strings[i] = strdup(string);
0 голосов
/ 07 января 2019

У вас много ошибок

  1. (char*)malloc(sizeof(char)*(strlen(string) **+ 1**)). Вы должны зарезервировать память на '\0'
  2. Очень неправильно

    memory = string;

    Чтобы скопировать строки, вам нужно ввести usr strcpy (в настоящее время правильная функция strncpy более безопасна)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...