Как динамически выделить строку с помощью функции void?

Прежде всего, спасибо, что посетили мой вопрос... :)

Меня интересует конкурентное программирование, поэтому я ежедневно решаю некоторые задачи, однако я знаю только язык 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.

Когда-то функция void называлась subroutine и использовалась для того, что называется side effects... Одним из преимуществ написания функций, возвращающих значения, является то, что они могут стать строительными блоками. y = f(x)... Функции должны возвращать полезные значения, имхо.

Fe2O3 08.01.2023 06:45

@Fe2O3 IIRC, BITD C не было void.

chux - Reinstate Monica 08.01.2023 07:13

@chux-ReinstateMonica «Раньше» (и тем более сейчас) C был не единственным ребенком в квартале, а «подпрограмма» была частью общеупотребительного языка.

Fe2O3 08.01.2023 07:20

@ Fe2O3 Согласен насчет подпрограммы. Вопрос о наличии ключевого слова void функция`.

chux - Reinstate Monica 08.01.2023 07:22

@chux-ReinstateMonica Является ли возврат void оксюмороном? C 2017 любопытно рассказывает об этом.

Allan Wind 08.01.2023 07:34

Предложите getchar() (или getc(FILE *stream) или fgetc(FILE *stream)) вместо вариативного scanf() со спецификатором формата "%c". Далее, как долго может быть ваша строка, не содержащая пробелов? Самое длинное слово в полном словаре — 29 символов, самое длинное слово в медицинском словаре — 45 символов. Даже если у вас может быть до 8 000 символов и более, рассмотрите однократное чтение в автоматическое хранилище с помощью fgets() (или scanf("%[width-1]s", ..)), а затем выделите и скопируйте в новый блок, а не realloc() каждый символ.

David C. Rankin 08.01.2023 08:55

@DavidC.Rankin Хммм, s в "%[width-1]s"??

chux - Reinstate Monica 08.01.2023 15:11

@chux-ReinstateMonica - модификатор ширины поля .... извините, это было неясно. Я думал о том, чтобы попробовать какой-то другой способ выделить это в фиксированном тексте, но это было лучшее, что я придумал...

David C. Rankin 09.01.2023 08:29
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку C передает аргументы по значению, чтобы что-то вернуть через выходной параметр, вам нужно передать указатель на него. Таким образом, чтобы вернуть char *, это будет:

void create_string(char **s) {
  *s = malloc(42);
}

Вот ваш рефакторинговый код. Я изменил следующее:

  1. Удалите возвращаемое значение вызывающего объекта обновления.
  2. Инициализируйте *ptr = malloc(1) для завершающего '\ 0'. Это устраняет ненужные и определенные реализации malloc(0). Это также устраняет (*ptr)[size] = ..., который выглядит неправильно, поскольку ожидается, что последний индекс будет size - 1. В качестве альтернативы инициализируйте его NULL.
  3. Используйте символьные константы вместо магических значений (32, 10).
  4. sizeof(char) определяется как 1, поэтому оставьте его.
  5. Уменьшена область действия переменной c.
  6. free() выделенная память.
  7. (косметика) Используйте size_t size вместо unsigned int size.
  8. (косметика) Избегайте шума литья 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);
}

Я не исправил эти проблемы:

  1. Проверьте возвращаемое значение malloc(), realloc().
  2. v = realloc(v, ...) небезопасен и приведет к утечке памяти в случае сбоя realloc(). Нужно сделать char *tmp = realloc(v,...); if (!tmp) { // err }; v = tmp;.
  3. Проверьте возвращаемое значение scanf(), иначе вы можете работать с неинициализированными данными.
  4. Используйте scanf("%s", ..) вместо for(;;) { scanf("%c", ...). Более эффективно выделять фрагменты за раз, а не побайтно.
  5. Если пользователь введет ctrl-d (EOF), программа войдет в бесконечный цикл.
  6. Это хорошая идея, чтобы отделить ввод-вывод от логики (т. е. позволить вызывающей стороне сделать scanf(). Таким образом, create_string() гораздо удобнее использовать повторно.

Это не работает, я заменил ptr на *ptr в коде, показанном в вопросе, и передал &str как aarg, использовал прототип как void creat_string(char **ptr), что привело к ошибке «Ошибка сегментации».

Soham Jobanputra 08.01.2023 06:46

@SohamJobanputra В вашем обновленном коде есть *ptr[size] = '\0';?

chux - Reinstate Monica 08.01.2023 06:48

@SohamJobanputra Я не могу воспроизвести вашу ошибку сегментации (см. Выше). Предоставьте трассировку стека.

Allan Wind 08.01.2023 06:57

Спасибо, @AllanWind, вы решили эту проблему!

Soham Jobanputra 08.01.2023 09:56

Другие вопросы по теме