Как считать строку неизвестной длины в си
Перейти к содержимому

Как считать строку неизвестной длины в си

  • автор:

Как выделить память для строки неизвестной длины?

Нужно считать из stdin строку (заканчивается \n),длина которой неизвестна.
Т.е. может быть
agdadsgasdfasdf
Или
asjdfhkasljdfhasd.
Я попытался сделать что-то такое, но получается, что, когда я получаю новый символ, массив chars переопределяется.

#include #include int main() < char *chars; int c,n=0; while((c=getchar()) != '\n')< chars = (char*)malloc(++n * sizeof(char)); chars[n-1] = c; >printf("%s\n", chars); >
  • Вопрос задан более трёх лет назад
  • 1740 просмотров

Комментировать

Решения вопроса 0

Ответы на вопрос 2

«I’m here to consult you» © Dogbert

Как это усовершенствовать?

An optional ‘m’ character. This is used with string conversions (%s, %c, %[), and relieves the caller of the need to allocate a corresponding buffer to hold the input: instead, scanf() allocates a buffer of sufficient size, and assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char * variable (this variable does not need to be initialized before the call). The caller should subsequently free(3) this buffer when it is no longer required.

#include int main()

Ответ написан более трёх лет назад

Комментировать

Нравится 2 Комментировать

Сергей Горностаев @sergey-gornostaev Куратор тега C

Седой и строгий

const unsigned int MAX_LENGTH = 1 * 1024 * 1024; // Не выделять больше мегабайта памяти const unsigned int CHUNK_SIZE = 1024; // Выделять блоками по килобайту int main() < unsigned int str_len = CHUNK_SIZE; char *str_ptr = malloc(CHUNK_SIZE); // Выделяем первый килобайтный блок if (str_ptr == NULL) err(EXIT_FAILURE, "Не удалось выделить память!\n"); int c; unsigned int i; for (i = 0, c = EOF; (c = getchar()) != '\n' && c != EOF; i++) < str_ptr[i] = c; if (i == MAX_LENGTH) < free(str_ptr); err(EXIT_FAILURE, "Слишком много входных данных!\n"); >if (i == str_len) < // Блок заполнен str_len = i + CHUNK_SIZE; str_ptr = realloc(str_ptr, str_len); // Расширяем блок на ещё один килобайт >> str_ptr[i] = '\0'; // Признак конца строки printf("%s\n", str_ptr); free(str_ptr); str_ptr = NULL; return EXIT_SUCCESS; >

Ответ написан более трёх лет назад

Комментировать

Нравится 1 Комментировать

Ваш ответ на вопрос

Войдите, чтобы написать ответ

cpp

  • C++
  • +1 ещё

В чем ошибка кода?

  • 1 подписчик
  • 11 часов назад
  • 100 просмотров

Ввод строки неизвестной длины в С (Именно С)

Как ввести строку с неизвестным количеством символов? Даже нет представления как использовать malloc и realloc, если в этих функциях тоже указывается размер или на сколько увеличить, а мне надо именно просто ввести строку, нажать Enter и все.

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Ввод строки неизвестной длины
Собственно на вход подается строка неизвестной длины, ввод которой оканчивается переходом на новую.

Ввод массива неизвестной длины
Добрый день! Уважаемые знатоки, вопрос скорее всего тривиальный, но тем не менее решения у меня.

Ввод массива заранее неизвестной длины
#include <iostream> #include <math.h> using namespace std; int main() < int arr, a = 0;.

Ввод динамического массива неизвестной длины
Нужно создать динамический массив целых чисел, размер которого неизвестен, а каждое введенное число.

2581 / 1681 / 909
Регистрация: 16.10.2013
Сообщений: 4,956
Записей в блоге: 14

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include #include int main() { char *str = NULL, c; int len = 1; str = (char*) malloc(sizeof(char)); printf("input string: "); while((c = getchar()) != '\n') { str[len - 1] = c; len++; str = (char*) realloc(str, len); } str[len - 1] = '\0'; printf("%s (%d symbols)\n", str, len - 1); free(str); return 0; }

Эксперт CЭксперт С++

11126 / 6084 / 1663
Регистрация: 18.10.2014
Сообщений: 15,294

ЦитатаСообщение от RabotnikMAKA Посмотреть сообщение

а мне надо именно просто ввести строку, нажать Enter и все.

В стандартной библиотеке такой возможности нет.

В POSIX реализациях есть getline , которая делает именно то, что вы хотите, но это — нестандартное расширение

1 2 3 4 5
char *s = NULL; size_t n = 0; n = getline(&s, &n, stdin); . free(s);

3802 / 2354 / 413
Регистрация: 09.09.2017
Сообщений: 10,208
из man scanf

char *buf; scanf("%as", &buf);

Если нужно с пробелами и всем прочим, можно пошаманить с форматной строкой.

Эксперт функциональных языков программированияЭксперт Python

36833 / 19881 / 4166
Регистрация: 12.02.2012
Сообщений: 33,015
Записей в блоге: 13
RabotnikMAKA, для размера строки верхняя граница есть?

Эксперт C

27695 / 17314 / 3809
Регистрация: 24.12.2010
Сообщений: 38,979

ЦитатаСообщение от Catstail Посмотреть сообщение

для размера строки верхняя граница есть?

Если была бы, то и вопроса бы не было
long399, Выделение памяти — операция достаточно дорогая. И перевыделять ее для каждого нового символа — не самое удачное решение.. Обычно выделяют память кусками. И следят за заполненностью выделенной области. Собственно, кажется, наподобие этого в С++ работает vector и string. Определение размера приращение — дело интуиции и здравого смысла.
Где-то уже обсуждалась эта тема. Найду — покажу.

Добавлено через 3 минуты
Нашлось на удивление легко. Просто первая ссылка в «Похожих темах»
Ввод строки неизвестной длины
Там есть и ссылка на более элегантное решение.

Как считать строку неизвестной длины в си

Доброго времени суток.
Нужно описать массив неизвестного количества строк неизвестной длины в Си. Пока имею следующее решение (код примерный, так как он на рабочем компе)
/* Глобальная переменная*/
char *mass[]; /* Функция, генерирующая новую строку в массиве*/
int new_mass_str(char* str, int num)
{
mass[num] = (char *)malloc(sizeof(str));
} Работает до 432 malloc’a, на 433 выпадает с сегфаултом.
Что-то мне подсказывает, что фейл в объявлении глобальной переменной, но как ее по другому объявить — ума не приложу. И почему-то всегда именно 433-е выделение памяти (запись 433 строки) сегфолтит. Подробное описание задачи:
Используется inotify для слежением за директориями. Пишу рекурсивное наблюдение с помощью ftw(). Так как inotify не возвращает полный путь до файла, а только имя файла и номер дескриптора слежения[wd], где произошли изменения, то приходится писать массив путей, скоррелированный с дескрипторами наблюдения (что-то вроде path[wd]).
Если есть какие-то еще варианты — буду рад выслушать. Но решение вопроса о массиве тоже хотелось бы узнать. Заранее благодарен.

  • Массив строк неизвестной длины, pavlinux, 04:42 , 24-Сен-12, (1)
    • Массив строк неизвестной длины, trmt, 04:55 , 24-Сен-12, (2)
      • Массив строк неизвестной длины, pavlinux, 05:15 , 24-Сен-12, (3)
      • Массив строк неизвестной длины, Аноним, 08:45 , 24-Сен-12, (5)
        • Массив строк неизвестной длины, trmt, 18:14 , 24-Сен-12, (6)
        • Массив строк неизвестной длины, Аноним, 18:56 , 25-Сен-12, ( 10 )
          • Массив строк неизвестной длины, Аноним, 19:06 , 25-Сен-12, ( 11 )
          • Массив строк неизвестной длины, trmt, 19:12 , 25-Сен-12, ( 12 )
            • Массив строк неизвестной длины, Andrey, 18:55 , 29-Сен-12, ( 13 )

            Сообщения по теме [Сортировка по времени | RSS]

            > Доброго времени с уток.

            1. Пока не напишешь своей ОС, не юзай указатели на массивы!
            2. sizeof(char *str) == SIZE_OF_CHAR

            >> Доброго времени с уток.
            > 1. Пока не напишешь своей ОС, не юзай указатели на массивы!
            > 2. sizeof(char *str) == SIZE_OF_CHAR

            Опс, извиняюсь

            не так написал.
            .
            mass[num] = (char *) malloc (strlen(str));
            .

            >[оверквотинг удален]
            > 433-е выделение памяти (запись 433 строки) сегфолтит.
            > Подробное описание задачи:
            > Используется inotify для слежением за директориями. Пишу рекурсивное наблюдение с помощью
            > ftw(). Так как inotify не возвращает полный путь до файла, а
            > только имя файла и номер дескриптора слежения[wd], где произошли изменения, то
            > приходится писать массив путей, скоррелированный с дескрипторами наблюдения (что-то вроде
            > path[wd]).
            > Если есть какие-то еще варианты — буду рад выслушать. Но решение вопроса
            > о массиве тоже хотелось бы узнать.
            > Заранее благодарен.

            Решил проблему:

            char** mass;
            int mass_size = 0;
            .
            int new_mass_str(char* str, int num)
            {
            if (mass == NULL)
            {
            mass_size = strlen(str);
            mass = (char**) malloc(mass_size);
            }
            else
            {
            mass_size = mass_size + strlen(str);
            mass = (char**)realloc(mass, mass_size);
            }
            .
            mass[num] = (char *)malloc(sizeof(str));
            }

            оказалось все просто и логично.

            > оказалось все просто и логично.

            И что самое весёлое — абсолютно неправильно. Впрочем запусти да и увидишь 🙂

            > И что самое весёлое — абсолютно неправильно. Впрочем запусти да и увидишь
            > 🙂

            ну по крайней мере дерево из 700+ каталогов, то есть 700+ строк в массив записалось, прочиталось.
            при нужде удалилось, добавилось. без ошибок и каких-либо видимых косяков.
            может стоит все же подробнее описывать, в чем человек не прав, а не строить из себя «мистер_я_лучше_Вас»? Уж простите.

            >[оверквотинг удален]
            > else
            > {
            > mass_size = mass_size +
            > strlen(str);
            > mass = (char**)realloc(mass, mass_size);
            > }
            > .
            > mass[num] = (char *)malloc(sizeof(str));
            > }
            > оказалось все просто и логично.

            Ваше первое решение было бессмыссленным
            char *mass[]; — в области статитеских данных компилятор определил указатель на массив разменом в один элемент. При этом, скорее всего, выдал предупреждение, которое вы проигнорировали.
            после этого mass[1] уже обращается к мусору. Удивительно, что программа вообще как-то работала.
            Вам бы помогло
            char (*mass)[]; или char **mass;
            но этом случае память нужно выделять и под сам mass, и под стороки.

            Во втором случат память вы выделяете дважды и к мусору (в том случае, если длины строк больше длин указателей) не обращаетесь, но программа тем не менее абсолютно безграмотна, так как при коротких строках может выдать тот же сегментэйшин фаулт, а при длинных выделяет памяти почти вдвое больше, чем нужно.

            Советую вам либо серьезнее отнестись к изучению основ языка C, либо подобрать другой язык, напритер Питон или Яву.

            > оказалось все просто и логично.

            Оно точно работает?

            Спасибо Анониму за подробное описание фейлов.
            как я понял, закосячил я в выделении памяти под массив указателей.
            Нужно в mass выделять память для указателей, а уже в mass[X] выделять память под строку.
            Итог получился такой.

            char** mass;
            int mass_cnt = 1; // количество строк (указателей)
            .
            int new_mass_str(char* str, int num)
            {
            if (mass == NULL)
            {
            mass = (char**) malloc(mass_cnt*sizeof(char *));
            }
            else
            {
            mass = (char**)realloc(mass, ++mass_cnt*sizeof(char *));
            }
            .
            mass[num] = (char *)malloc(strlen(str)+1); // вот тут я в предыдущем варианте опечатался
            // strlen конечно же
            }

            Работает, памяти жрет намного меньше (для 715 строк уменьшение почти в 9 раз).

            Где-то я опять закосячил?

            > Спасибо Анониму за подробное описание фейлов.

            Правильное восприятие критики обнадеживает.

            > Где-то я опять закосячил?

            На этот раз практически все верно, если я чего не пропустил.
            Еще бы:
            1. Инициализировать mass нулем.
            2. Проверять ошибки.
            3. Реаллок делать не для каждой строки, а память добавлять кусками, допустип, сторок по 256.
            4. Вместо глобальных переменных использовать статическую структуру внутри функции.
            .
            То уже почти библиотечная реализация.

            А если в задаче разрешено использовать C++, то в stl можно найти почти готовое решение.

            В догонку.
            Непонятно, зачем передавать функции номер строки, если есть глобальный счетчик.

            >[оверквотинг удален]
            > Еще бы:
            > 1. Инициализировать mass нулем.
            > 2. Проверять ошибки.
            > 3. Реаллок делать не для каждой строки, а память добавлять кусками, допустип,
            > сторок по 256.
            > 4. Вместо глобальных переменных использовать статическую структуру внутри функции.
            > .
            > То уже почти библиотечная реализация.
            > А если в задаче разрешено использовать C++, то в stl можно найти
            > почти готовое решение.

            mass нулем и обработку ошибок уже сделал (с работы нет постоянного доступа, поэтому тут набегами =) )
            вот с добавлением кусками проблема. ftw() идет вниз по дереву иерархии и возвращает имена файлов и директорий. каждую директорию я сразу же начинаю отслеживать inotify’ем, и поэтому сразу добавляю ее в массив по номеру дескриптора. пока быстродействие инициализации не критично. когда доделаю полный функционал, там уже оптимизировать начну.

            спасибо за помощь

            > mass нулем и обработку ошибок уже сделал (с работы нет постоянного
            > доступа, поэтому тут набегами =) )
            > вот с добавлением кусками проблема. ftw() идет вниз по дереву иерархии
            > и возвращает имена файлов и директорий. каждую директорию я сразу же
            > начинаю отслеживать inotify’ем, и поэтому сразу добавляю ее в массив по
            > номеру дескриптора. пока быстродействие инициализации не критично. когда доделаю полный
            > функционал, там уже оптимизировать начну.
            > спасибо за помощь

            Вам бы врачем работать или адвокатом. Много, умно, и не по теме (это про массив строк неизвестной длины).

            ЗЫ Прочитал название темы, на полке прямо передо мной Хээфилд и проч. лежит. Последнее сообщение просто убило. Ну, понятно, что если бы всю тему прочитал, то наверное понял бы. Но тут слишком эээ. «жесть».

            Как считать строку неизвестной длины в си

            Для того, чтобы с помощь scanf() ввести строку, необходимо выделить для этого память. А если неизвестно, какова длина строки, то невозможно выделить правильное количество памяти. Как решать такую проблему?

            char* str; scanf("%s", str);

            Код не работает, потому что необходимо выделить память, куда будут записываться символы. То есть

            char* str; str = new char [n]; scanf("%s", str);

            где n — количество символов. Но! Если это самое количество неизвестно? P.S. Если тема уже обсуждалась то не тыкайте в поиск, я искал — не нашел. Заранее спасибо.

            Помогли тебе — помоги другому.
            Delphi Warrior
            Регистрация: 15.08.2008
            Сообщений: 2,501
            Вам обязательно Сишный ввод? Или С++ тоже можно?

            Mess with the best, die like the rest. (с) Hackers
            Лабораторные, курсовые на Delphi\Pascal\C++
            ya.flex-freelance@yandex.ru Icq — 636-954-303

            Hacker19_90
            Посмотреть профиль
            Найти ещё сообщения от Hacker19_90

            Лжец и смутьян
            Форумчанин
            Регистрация: 03.04.2009
            Сообщений: 194
            Помогли тебе — помоги другому.
            C++,DirectX/OpenGL
            Форумчанин
            Регистрация: 09.01.2011
            Сообщений: 422
            Сообщение от Alt

            Для того, чтобы с помощь scanf() ввести строку, необходимо выделить для этого память. А если неизвестно, какова длина строки, то невозможно выделить правильное количество памяти. Как решать такую проблему?

            Использовать контейнеры переменной длины и по символу из потока копировать:

            #include #include using namespace std; string str; while (1) < str+= cin.get(); if ( str.find("\n") != -1) //пока не будет переход строки break; >

            Лжец и смутьян
            Форумчанин
            Регистрация: 03.04.2009
            Сообщений: 194
            An1ka, большое спасибо! Работает идеально.
            Только цикл можно лаконичнее записать:

            do str+= cin.get(); while ( str.find("\n") != -1);

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *