Как динамически выделить пространство памяти для строки и получить эту строку от пользователя? - PullRequest
41 голосов
/ 17 ноября 2011

Я хочу прочитать ввод от пользователя, используя программу C. Я не хочу использовать массив, как,

char names[50];

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

Если я использую указатель символов, как,

char *names;

тогда мне нужно выделить память для этого таким образом,

names = (char *)malloc(20 * sizeof(char));

В этом случае также возможна потеря памяти.

Итак, мне нужно динамически выделить память для строки, которая точно равна длине строки.

Предположим,

Если пользовательский ввод "stackoverflow", то выделенная память должна быть 14 (т.е. длина строки = 13 и 1 дополнительный пробел для '\ 0').

Как мне этого добиться?

Ответы [ 11 ]

40 голосов
/ 17 ноября 2011

Читайте по одному символу за раз (используя getc(stdin)) и увеличивайте строку (realloc) по мере продвижения.

Вот функция, которую я написал некоторое время назад. Обратите внимание, что он предназначен только для ввода текста.

char *getln()
{
    char *line = NULL, *tmp = NULL;
    size_t size = 0, index = 0;
    int ch = EOF;

    while (ch) {
        ch = getc(stdin);

        /* Check if we need to stop. */
        if (ch == EOF || ch == '\n')
            ch = 0;

        /* Check if we need to expand. */
        if (size <= index) {
            size += CHUNK;
            tmp = realloc(line, size);
            if (!tmp) {
                free(line);
                line = NULL;
                break;
            }
            line = tmp;
        }

        /* Actually store the thing. */
        line[index++] = ch;
    }

    return line;
}
6 голосов
/ 17 ноября 2011

Вы можете иметь массив, который начинается с 10 элементов.Читайте ввод за символом.Если это пройдет, перераспределите еще 5.Не самый лучший, но потом вы можете освободить другое место позже.

5 голосов
/ 31 августа 2015

Вы также можете использовать регулярное выражение, например, следующий фрагмент кода:

char *names
scanf("%m[^\n]", &names)

получит всю строку из stdin, динамически выделяя количество места, которое оно занимает.После этого, конечно, вам нужно бесплатно names.

5 голосов
/ 17 ноября 2011

Если вам нужно сэкономить память, каждый раз читайте char за char и realloc. Производительность умрет, но вы сэкономите эти 10 байтов.

Другим хорошим компромиссом является чтение функции (с использованием локальной переменной), а затем копирование. Таким образом, большой буфер будет иметь функциональную область.

2 голосов
/ 22 сентября 2014

Ниже приведен код для создания динамической строки:

void main()
{
  char *str, c;
  int i = 0, j = 1;

  str = (char*)malloc(sizeof(char));

  printf("Enter String : ");

  while (c != '\n') {
    // read the input from keyboard standard input
    c = getc(stdin);

    // re-allocate (resize) memory for character read to be stored
    str = (char*)realloc(str, j * sizeof(char));

    // store read character by making pointer point to c
    str[i] = c;

    i++;
    j++;
  }

  str[i] = '\0'; // at the end append null character to mark end of string

  printf("\nThe entered string is : %s", str);

  free(str); // important step the pointer declared must be made free
}
1 голос
/ 04 августа 2016
char* load_string()
 {

char* string = (char*) malloc(sizeof(char));
*string = '\0';

int key;
int sizer = 2;

char sup[2] = {'\0'};

while( (key = getc(stdin)) != '\n')
{
    string = realloc(string,sizer * sizeof(char));
    sup[0] = (char) key;
    strcat(string,sup);
    sizer++

}
return string;

}

int main()
  {
char* str;
str = load_string();

return 0;
  }
0 голосов
/ 08 июня 2019

realloc - довольно дорогое действие ... вот мой способ получения строки, соотношение realloc не 1: 1:

char* getAString()
{    
    //define two indexes, one for logical size, other for physical
    int logSize = 0, phySize = 1;  
    char *res, c;

    res = (char *)malloc(sizeof(char));

    //get a char from user, first time outside the loop
    c = getchar();

    //define the condition to stop receiving data
    while(c != '\n')
    {
        if(logSize == phySize)
        {
            phySize *= 2;
            res = (char *)realloc(res, sizeof(char) * phySize);
        }
        res[logSize++] = c;
        c = getchar();
    }
    //here we diminish string to actual logical size, plus one for \0
    res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
    res[logSize] = '\0';
    return res;
}
0 голосов
/ 22 декабря 2018

Это фрагмент функции, который я написал, чтобы отсканировать пользовательский ввод на наличие строки и затем сохранить эту строку в массиве того же размера, что и пользовательский ввод.Обратите внимание, что я инициализирую j значением 2, чтобы иметь возможность хранить символ '\ 0'.

char* dynamicstring() {
    char *str = NULL;
    int i = 0, j = 2, c;
    str = (char*)malloc(sizeof(char));
    //error checking
    if (str == NULL) {
        printf("Error allocating memory\n");
        exit(EXIT_FAILURE);
    }

    while((c = getc(stdin)) && c != '\n')
    {
        str[i] = c;
        str = realloc(str,j*sizeof(char));
        //error checking
        if (str == NULL) {
            printf("Error allocating memory\n");
            free(str);
            exit(EXIT_FAILURE);
        }

        i++;
        j++;
    }
    str[i] = '\0';
    return str;
}

В main () вы можете объявить другую переменную char * для хранения возвращаемого значения dynamicstring() и затем освободите эту переменную char *, когда вы закончите, используя ее.

0 голосов
/ 05 августа 2018

Сначала определите новую функцию для чтения ввода (в соответствии со структурой вашего ввода) и сохраните строку, что означает использование памяти в стеке. Установите длину строки, достаточную для ввода.

Во-вторых, используйте strlen, чтобы измерить точную использованную длину строки, сохраненной ранее, и malloc, чтобы выделить память в куче, длина которой определяется strlen. Код показан ниже.

int strLength = strlen(strInStack);
if (strLength == 0) {
    printf("\"strInStack\" is empty.\n");
}
else {
    char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
    strcpy(strInHeap, strInStack);
}
return strInHeap;

Наконец, скопируйте значение strInStack в strInHeap, используя strcpy, и верните указатель в strInHeap. strInStack будет автоматически освобожден, поскольку он выходит только из этой подфункции.

0 голосов
/ 31 марта 2018

Вот фрагмент кода, который я написал и который выполняет те же функции.

Этот код похож на тот, что написан Кунал Вадхва .

char *dynamicCharString()
{
char *str, c;
int i;
str = (char*)malloc(1*sizeof(char));

while(c = getc(stdin),c!='\n')
{
    str[i] = c;
    i++;
    realloc(str,i*sizeof(char));
}
str[i] = '\0';
return str;
}
...