Прежде всего, спасибо, что посетили мой вопрос... :)
Меня интересует конкурентное программирование, поэтому я ежедневно решаю некоторые задачи, однако я знаю только язык C на приличном уровне, и я часто сталкиваюсь с проблемами при динамическом размещении чего-либо, как обычно, особенно для строк и 2D-массивов.
Но мне каким-то образом удается найти способы (благодаря StackOverflow), например, я хотел создать функцию, которая динамически сканирует строку, пока пользователь не введет пробел или новую строку, поэтому я придумал решение ниже, и оно отлично работает:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
А теперь из любопытства я хочу знать, как я могу сделать то же самое, используя функцию void?, что-то вроде:
char *str;
create_string(&str);
должен начать хранить все в динамической памяти, на которую указывает str.
Кроме того, пожалуйста, если у вас есть больше знаний, чтобы продемонстрировать DMA для 2D-массива, пожалуйста, покажите мне это, не стесняйтесь приводить примеры с различными проблемами.
А также Как я могу остановить сканирование строки (которая была выделена динамически) с определенным окончанием строки? например, сканирование (любое сканирование, т. е. int, bool, пользовательские структуры и т. д.) должно останавливаться, если пользователь вводит строку «СТОП». Пожалуйста, не стесняйтесь приводить наглядные примеры.
Потому что я уверен, что этот вопрос горит как огонь в головах начинающих и продолжающих программистов C.
@Fe2O3 IIRC, BITD C не было void
.
@chux-ReinstateMonica «Раньше» (и тем более сейчас) C был не единственным ребенком в квартале, а «подпрограмма» была частью общеупотребительного языка.
@ Fe2O3 Согласен насчет подпрограммы. Вопрос о наличии ключевого слова void
функция`.
@chux-ReinstateMonica Является ли возврат void оксюмороном? C 2017 любопытно рассказывает об этом.
Предложите getchar()
(или getc(FILE *stream)
или fgetc(FILE *stream)
) вместо вариативного scanf()
со спецификатором формата "%c"
. Далее, как долго может быть ваша строка, не содержащая пробелов? Самое длинное слово в полном словаре — 29 символов, самое длинное слово в медицинском словаре — 45 символов. Даже если у вас может быть до 8 000 символов и более, рассмотрите однократное чтение в автоматическое хранилище с помощью fgets()
(или scanf("%[width-1]s", ..)
), а затем выделите и скопируйте в новый блок, а не realloc()
каждый символ.
@DavidC.Rankin Хммм, s
в "%[width-1]s"
??
@chux-ReinstateMonica - модификатор ширины поля .... извините, это было неясно. Я думал о том, чтобы попробовать какой-то другой способ выделить это в фиксированном тексте, но это было лучшее, что я придумал...
Поскольку C передает аргументы по значению, чтобы что-то вернуть через выходной параметр, вам нужно передать указатель на него. Таким образом, чтобы вернуть char *
, это будет:
void create_string(char **s) {
*s = malloc(42);
}
Вот ваш рефакторинговый код. Я изменил следующее:
*ptr = malloc(1)
для завершающего '\ 0'. Это устраняет ненужные и определенные реализации malloc(0)
. Это также устраняет (*ptr)[size] = ...
, который выглядит неправильно, поскольку ожидается, что последний индекс будет size - 1
. В качестве альтернативы инициализируйте его NULL
.sizeof(char)
определяется как 1, поэтому оставьте его.c
.free()
выделенная память.size_t size
вместо unsigned int size
.void *
.#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
Я не исправил эти проблемы:
malloc()
, realloc()
.v = realloc(v, ...)
небезопасен и приведет к утечке памяти в случае сбоя realloc()
. Нужно сделать char *tmp = realloc(v,...); if (!tmp) { // err }; v = tmp;
.scanf()
, иначе вы можете работать с неинициализированными данными.scanf("%s", ..)
вместо for(;;) { scanf("%c", ...)
. Более эффективно выделять фрагменты за раз, а не побайтно.ctrl-d
(EOF), программа войдет в бесконечный цикл.scanf()
. Таким образом, create_string()
гораздо удобнее использовать повторно.Это не работает, я заменил ptr на *ptr в коде, показанном в вопросе, и передал &str как aarg, использовал прототип как void creat_string(char **ptr), что привело к ошибке «Ошибка сегментации».
@SohamJobanputra В вашем обновленном коде есть *ptr[size] = '\0';
?
@SohamJobanputra Я не могу воспроизвести вашу ошибку сегментации (см. Выше). Предоставьте трассировку стека.
Спасибо, @AllanWind, вы решили эту проблему!
Когда-то функция
void
называласьsubroutine
и использовалась для того, что называетсяside effects
... Одним из преимуществ написания функций, возвращающих значения, является то, что они могут стать строительными блоками.y = f(x)
... Функции должны возвращать полезные значения, имхо.