#c #input #dynamic-memory-allocation
Вопрос:
Я создаю программу,в которой пользователь будет вводить строку неизвестного размера, если пользователь вводит «КОНЕЦ», то программа завершится, в противном случае она запросит другую строку и другую, поскольку размер строки неизвестен, я использовал динамическое распределение памяти, чтобы взять строку неизвестного размера, вот что я пробовал
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
int main()
{
bool on = true;
char *string;
while(on)
{
string = malloc(sizeof(char));
int i;
for (i = 0;; i )
{
int n;
n = getchar();
if (n == 'n')
{
break;
}
else
{
string = realloc(string, sizeof(char));
string[i] = (char)n;
}
}
string[i] = '';
if (strcmp(string, "END") == 0)
{
on = false;
}
printf("Len: [%i],String = %sn",i 1,string);
free(string);
}
return 0;
}
но если я ввожу строку размером более 25 или около того, программа выходит из строя, она выдает мне этот вывод
0 [main] get_the_line_dynamically 1056 cygwin_exception::open_stackdumpfile: Dumping stack trace to get_the_line_dynamically.exe.stackdump
но что не так с этим кодом??
Комментарии:
1. Ваш
realloc
вызов не увеличивает буфер; вы входитеsizeof(char)
, тем самым запрашивая «пожалуйста, измените размер этого на 1», что уже есть.2. Ты, наверное, хотел
realloc(string, i 2)
. Например, предположим, что вы прочитали ровно один символ ввода. В этом случае тело цикла выполняется один раз сi == 0
помощью . Буфер уже имеет размер 1, и поэтому его нужно увеличить до 2: для хранения символа atstring[0]
и завершающего байта null требуется два байтаstring[1]
.3. @ShahzadIftikhar
sizeof(char)
гарантированно будет 1.4. Используйте тип
size_t
дляi
, неint
, и следите за тем, чтобы он не обернулся или не стал слишком большим. Это хорошая идея, чтобы проверить возвращаемое значениеmalloc
иrealloc
для null.5. @Kaz, нет, это не очень хорошая идея для использования
sizeof(char)
, так как это ничего не упрощает — вам все равно придется найти все места, гдеsizeof(char)
это сделано, и выяснить, нужно ли их менять или нет. Если вы хотите улучшить свою программу в будущем, вы можете использоватьsizeof(*string)
.
Ответ №1:
realloc()
выделяет указанный вами размер и при увеличении размера копирует данные из исходного распределения в новое распределение, а затем возвращает старые данные в кучу. Это не увеличение размера, который вы передаете, это абсолютный размер, а не увеличение размера.
Таким образом, вам нужно :
string = realloc( string, i 2 ) ;
Однако увеличение в отдельных байтах ужасно неэффективно, требует выделения, копирования данных и бесплатно для каждого отдельного байта. Обычный процесс состоит в том, чтобы увеличить емкость большими порциями и увеличить выделение только в том случае, если текущая емкость превышена. Так что вы могли бы:
#define STRING_CAPACITY_INCREMENT 32
size_t string_capacity = STRING_CAPACITY_INCREMENT ;
char* string = malloc( string_capacity ) ;
Затем:
// If insufficient capacity for new character plus NUL...
if( i 2 > string_capacity )
{
string_capacity = STRING_CAPACITY_INCREMENT ;
string = realloc(string, string_capacity );
}
string[i] = (char)n;
Это повысит производительность по времени, но в случае, если вас беспокоит использование памяти, имейте в виду, что распределение памяти выровнено по 8 байтам, поэтому приращение одного байта ничего не экономит по сравнению, например, с увеличением емкости на 8. Также по этой причине приращение также должно быть кратным 8.
В некоторых случаях вы можете выбрать экспоненциальное увеличение емкости, например удвоение: 8, 16, 32, 64 и т.д. до некоторого разумного предела, после чего он становится линейным. Это может быть лучше с точки зрения балансировки производительности и использования памяти, если у вас много маленьких строк и всего несколько длинных.
Комментарии:
1. примечание по правописанию: «имейте в виду», буквально, чтобы иметь в виду.
2. @TimRandall исправил — больше опечаток, чем незнания. Хорошее место.
3. Приращения в один байт действительно кое-что спасают: сложность кода. Рост обрабатывается одной
realloc
строкой, выданной безоговорочно.4. @Kaz Правда, в этом тривиальном примере это менее сложно, и производительность, возможно, не является проблемой, если ввод осуществляется вручную, а строки короткие. Однако в любом значимом приложении это не было бы привычкой, которую вы хотели бы применять повсеместно. Проблема, если сложность легко решается, например, типом структуры строкового буфера и функцией обертывания расширения. Но на самом деле именно поэтому существует C .