it-swarm.com.ru

Как динамически выделить пространство памяти для строки и получить эту строку от пользователя?

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

char names[50];

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

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

char *names;

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

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

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

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

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

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

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

41
Dinesh

Читайте по одному символу за раз (используя 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;
}
40
cnicutar

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

6
tekknolagi

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

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

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

5
Jytug

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

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

5
BigMike

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

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
Kunal Wadhwa
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;
  }
1
Shihan

Это фрагмент функции, который я написал, чтобы отсканировать пользовательский ввод на наличие строки и затем сохранить эту строку в массиве того же размера, что и пользовательский ввод. Обратите внимание, что я инициализирую 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
André Fael

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

Этот код похож на тот, который написал Kunal Wadhwa .

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;
}
0
user8311083

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

Во-вторых, используйте 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
Edward Xu

Это более простой подход

char *in_str;
in_str=(char *)malloc(512000 * sizeof(char));
scanf("\n%[^\n]",in_str);
0
Kiran JD