Как динамически распределять пространство памяти для строки и получать эту строку от пользователя?
Я хочу читать данные от пользователя, используя программу C. Я не хочу использовать массив, например,
char names[50];
потому что если пользователь задает строку длиной 10, остальные пробелы теряются.
Если я использую указатель символа, например,
char *names;
тогда мне нужно выделить память для этого таким образом,
names = (char *)malloc(20 * sizeof(char));
В этом случае также существует возможность потери памяти.
Итак, мне нужно динамически выделять память для строки, которая точно такая же, как длина строки.
Предположим, что
Если пользовательский ввод "stackoverflow"
, то выделенная память должна быть 14
(т.е. Длина строки = 13 и 1 дополнительное пространство для '\ 0').
Как я мог достичь этого?
Ответы
Ответ 1
Прочитайте по одному символу за раз (используя 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;
}
Ответ 2
У вас может быть массив, который начинается с 10 элементов. Прочитать входной символ по символу. Если это произойдет, перераспределите еще 5. Не самое лучшее, но потом вы можете освободить другое пространство позже.
Ответ 3
Если вам нужно освободить память, прочитайте char на char и перераспределите каждый раз. Производительность умрет, но вы пощадите это 10 байт.
Другим хорошим компромиссом является чтение в функции (с использованием локальной переменной), а затем копирование. Таким образом, большой буфер будет обладать функциями.
Ответ 4
Вы также можете использовать регулярное выражение, например следующий фрагмент кода:
char *names
scanf("%m[^\n]", &names)
получит всю строку из stdin, динамически распределяя объем пространства, который он занимает. После этого, конечно, вам нужно освободить names
.
Ответ 5
Ниже приведен код для создания динамической строки:
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
}
Ответ 6
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;
}
Ответ 7
Это более простой подход
char *in_str;
in_str=(char *)malloc(512000 * sizeof(char));
scanf("\n%[^\n]",in_str);
Ответ 8
Вот фрагмент, который я написал, который выполняет те же функции.
Этот код похож на тот, который написал Кунал Вадхва.
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;
}
Ответ 9
Сначала определите новую функцию для чтения ввода (в соответствии со структурой вашего ввода) и сохранения строки, что означает использование памяти в стеке. Установите длину строки, достаточную для ввода.
Во-вторых, используйте 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
будет освобожден автоматически, потому что он выходит только из этой strInStack
.
Ответ 10
Это фрагмент функции, который я написал, чтобы отсканировать пользовательский ввод на наличие строки и затем сохранить эту строку в массиве того же размера, что и пользовательский ввод. Обратите внимание, что я инициализирую 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 *, когда вы закончите ее использовать.
Ответ 11
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;
}