Я хотел написать программу на C, которая будет принимать строку любой длины из stdin
и отображать ее или применять любую функцию к этой строке. Чтобы это работало, мне понадобится строка (char []
) с динамической длиной.
Вот как я это сделал:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
char *line;
line = malloc(10);
line[0] = '\0';
char *str = malloc(10);
fprintf(stdout, "Please enter your line:\n");
while(fgets(str, 10, stdin)){
//check for line break
if (str[strlen(str)-1] == '\n'){
str[strlen(str) - 1] = '\0';
strcat(line, str);
break;
}
strcat(line, str);
line = realloc(line, strlen(line) + 10);
str = realloc(str, strlen(str) + 10);
}
fprintf(stderr, "you entered %s\n", line);
//just for testing
/*
fprintf(stderr, "\n str= %s \n", str );
fprintf(stderr, "\n line= %s \n", line);
*/
free(line);
free(str);
exit(EXIT_SUCCESS);
}
Однако это выглядит ужасно. Мне нужно два массива символов. В char *str
я буду записывать ввод со стандартного ввода и объединять его с char *line
. str
будет содержать только до 10 байтов символов, и поэтому мне нужно объединить все в line
.
Есть ли более чистый способ сохранить вывод из stdin
в этом случае и применить к нему какую-то функцию? Я делаю это неправильно? Можно ли обойтись без malloc
и realloc
?
И затем вы создали довольно типичную функцию C. Обычно вы делаете str
степенью двойки, например 1024
, или BUFSIZE
, потому что ЦП такой.
"примет строку любой длины из стандартного ввода" --> как насчет чего-то более устойчивого к хакерским атакам, например, "примет строку любой длины из стандартного ввода до 1 Мбайта"?
@chux Реализация библиотеки C и / или ядро уже справятся с этим за вас. Если кто-то попытается ввести очень длинную строку, процесс будет остановлен из-за ошибки нехватки памяти (realloc
вернет NULL
).
Ничего ужасного в этом нет. В C вы должны управлять своей собственной памятью. Если вы не знаете, сколько вам нужно до времени выполнения, вам придется динамически распределять его, как есть. Вы также должны проверить возвращаемые значения malloc
и realloc
на случай, если они не сработают.
@YoYoYonnY Эксплойт, которого следует избегать, — это переполнение ресурсов, включая ресурсы памяти. Ждать NULL
на *alloc()
уже поздно.
@chux Определенно не верно для Linux, и я не эксперт по другим ядрам, но я полагаю, что они убьют процесс, бесполезно потребляющий ресурсы, как это делает Linux.
Это пример. Вам нужно добавить проверку результатов malloc и realloc (я не делал этого для простоты)
#include <stdio.h>
#include <stdlib.h>
#define CHUNK 32
char *readline(void)
{
size_t csize = CHUNK;
size_t cpos = 0;
char *str = malloc(CHUNK);
int ch;
while((ch = fgetc(stdin)) != '\n' && ch != '\r')
{
str[cpos++] = ch;
if (cpos == csize)
{
csize += CHUNK;
str = realloc(str, csize);
}
}
str[cpos] = 0;
return str;
}
int main()
{
printf("\n%s\n", readline());
return 0;
}
рабочий пример: https://onlinegdb.com/Sk9r4gOYV
Вы также должны освобождать выделенную память, когда она больше не нужна.
Вам не нужно
realloc(str)
, вы никогда не читаете более 10 байт за раз, вы можете просто определитьstr
какchar str[10]
.