строка Dynami c распределение в C - PullRequest
2 голосов
/ 19 июня 2020

Я пишу функцию, которая должна:

  1. Получать полное предложение от пользователя

  2. Динамически назначать каждому слову a блок памяти, который может его содержать

  3. Скопируйте его и сохраните адрес в * массив указателей слов

Я написал al oop что на каждой итерации получает слово из предложения, вставленного пользователем, но я не могу его правильно распределить динамически. Вот что у меня:

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

Мне также нужно убедиться, что:

  • Если функция завершается успешно, она возвращает количество введенных слов.

  • В случае сбоя выделения памяти функция возвращает -1.

Ответы [ 2 ]

2 голосов
/ 19 июня 2020

Условие while(scanf("%s", str) != EOF) является потенциально бесконечным l oop, это прекратится только в том случае, если вы загрузите в программу сигнал 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
}

Ограничения: не может быть пробелов после последнего введенного слова для завершения цикла.

Теперь, если вы хотите двумерный массив, подобный структуре, динамически выделяемый не только для самих слов, но и для указателей, указывающих на эти строки, вам понадобится нечто более особенное, тройной указатель.

Думайте об этом как об указателе на массив строк, это то, что вам нужно в качестве аргумента вашей функции, чтобы сделать изменения постоянными в вызывающей функции, в данном случае в основной функции.

Li ve 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
}

Ограничения: не может быть пробелов после последнего введенного слова для завершения цикла.

Обратите внимание, что там является дополнительным уровнем косвенности из-за того, что эти назначения выполняются через аргументы функции, если бы они использовались на месте или возвращались функцией, вам понадобился бы только простой указатель в первом примере и двойной указатель во втором примере.

0 голосов
/ 21 июня 2020

Предполагая, что следующие ограничения уже встроены в ваш фрагмент кода:

  • максимальная длина слова составляет 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;
}
...