Как сделать динамический массив слов в Си?
Мне поставили задачу сделать ввод текста по словам, которые будут храниться в words . Я понял, что char* words[] — это массив слов. Мне нужно, чтобы выделялось определенное количество байт для каждого слова (кажется, у меня это получилось сделать, но не так, как надо) Еще не получается остановить цикл ввода: не знаю как сделать условие остановки. Пробовал tmp != EOF и if(scanf(«%s», tmp) !=1);
#include #include #include #include #define WORDS_ARRAY_SIZE 100 #define MAX_STR_LEN 50 int main() < char* words[WORDS_ARRAY_SIZE]; for (int i = 0; i < WORDS_ARRAY_SIZE; i++) < words[i] = NULL; >char tmp[MAX_STR_LEN];//временный массив для слова for(int i = 0; i < WORDS_ARRAY_SIZE ; i++)< scanf("%s", tmp); //узнаю размер слова в массиве tmp и увеличиваю words[i] words[i] = (char *)malloc(sizeof(char)*(strlen(tmp))); if(words[i] == NULL)< printf("faill"); exit(0); >//здесь я попытался поместить tmp в words но это не работает words[i] = tmp; > free(words);//ругается на это return 0; >
И еще выдает ошибку SIGABRT в строке free(words);
Отслеживать
547 2 2 серебряных знака 13 13 бронзовых знаков
задан 19 авг 2021 в 11:08
Михаил Кузнецов Михаил Кузнецов
29 1 1 золотой знак 1 1 серебряный знак 6 6 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
- указатель на выделенную память вы меняете на адрес локального массива
words[i] = tmp;
,а нужно копирование строки с одного места памяти в другое с помощью
strcpy(words[i],tmp);
- удалять локальный массив вы не имеете права, вы память для него не выделяли
free(words);
всю память, что вы выделяли, от той и отказывайтесь
for(int i = 0; i < words_N ; i++) free (words[i]);
- память выделяли мало, не хватает для конечного символа конца строки '\00'
words[i] = (char *)malloc(sizeof(char)*(strlen(tmp) + 1));
if (strlen(tmp) == 1 && tmp[0] == 'X')
// gcc -std=c11 -Wall -Wextra -Wpedantic -Winline -Os words.c -o words #include #include #include #include #define WORDS_ARRAY_SIZE 100 #define MAX_STR_LEN 50 int main() < char* words[WORDS_ARRAY_SIZE]; for (int i = 0; i < WORDS_ARRAY_SIZE; i++) < words[i] = NULL; >char tmp[MAX_STR_LEN];//временный массив для слова int words_N = WORDS_ARRAY_SIZE ; for(int i = 0; i < WORDS_ARRAY_SIZE ; i++)< scanf("%s", tmp); // ключевое слово сделайте "X" для выхода if (strlen(tmp) == 1 && tmp[0] == 'X') < words_N = i ; break; >//узнаю размер слова в массиве tmp и увеличиваю words[i] // память выделяли мало, не хватает для конечного символа конца строки '\00' words[i] = (char *)malloc(sizeof(char)*(strlen(tmp) + 1)); if(words[i] == NULL) < printf("faill"); exit(0); >// указатель на выделенную память вы меняете на адрес локального массива // words[i] = tmp; // копируем строку из tmp в words[i] strcpy(words[i],tmp); > // free(words); // удалять локальный массив вы не имеете права, вы память для него не выделяли // всю память, что вы выделяли, от той и отказывайтесь for(int i = 0; i
Динамические массивы строк
Здравствуйте. Меня интересуют динамические массивы строк. У меня есть код, который и пробовал в qt+вижуал студио. Мне необходимо проверить, правильно ли я создаю эти строки, и тоже самое на векторах бы посмотреть.
// указатель на массив со строками: char **ptr_str_Stroki_Peremennyx_Tablitc; // размер массива строк.: int size_str_Stroki_Peremennyx_Tablitc; // размер массива строк. Сначалла у нас есть одна строка.: size_str_Stroki_Peremennyx_Tablitc = 2; // Создаем одну/несколько строк.: ptr_str_Stroki_Peremennyx_Tablitc = new char* [size_str_Stroki_Peremennyx_Tablitc] ; for (int i = 0; i < size_str_Stroki_Peremennyx_Tablitc; i++) < ptr_str_Stroki_Peremennyx_Tablitc[i] = new char[20]; // Под каждую строку выделяем массив в 20 символов. >; // Как увеличить массив строк? : ptr_str_Stroki_Peremennyx_Tablitc = (char **) realloc (ptr_str_Stroki_Peremennyx_Tablitc, 6*(sizeof(char *) ) ); // Потом добавлял новую строку: // Под каждую строку выделяем массив в 20 символов. ptr_str_Stroki_Peremennyx_Tablitc [2] = new char[20]; // Удаление массива строк.: for (int i = 0; i < size_str_Stroki_Peremennyx_Tablitc; i++) < delete[] ptr_str_Stroki_Peremennyx_Tablitc[i]; //free (ptr_str_Stroki_Peremennyx_Tablitc[i]); >free (ptr_str_Stroki_Peremennyx_Tablitc); // или delete[] ptr_str_Stroki_Peremennyx_Tablitc; // ?
Правильно или нет у меня сделано при выделении памяти? Еще можно на векторах
// динамический массив: std::vector v; // строка: std::string text("Hello"); // добавление в конец массива: v.push_back(text);
Проверьте пожалуйста правильно ли я делаю при создании/удалении массива строк. Чтобы не было проблем с памятью ОЗУ. С чем проще работать? Или если правильно сделано, то без разницы с чем работать?
20.02.2018 в 11:27 #4444
Тут почти все неправильно. Кстати, в будущем очень прошу при публикации кода на форуме давать более четкие имена переменных (на нормальном английском языке). Строки в С++
Принято говорить, что в языке Си строк не было. Вместо них использовали массивы символов:
char* str; На самом же деле, как не крути, во всех языках строки реализованы примерно так…
Важно, что память под строку ты должен выделить, не особо важно используешь ты new или malloc , но надо понимать, что если выделил с new – то освобождать надо оператором delete . А если с malloc – то функцией free . Кроме того, если выделил память с помощью под массив (как ты и делаешь) – то освобождать надо оператором delete[] . Рассмотрим простой пример:
int len; cin >> len; char* str = new char[len]; std::cin.getline(str, len); coutТут мы спросили у юзера длину строки, которую он хочет ввести, выделили память, считали строку, вывели ее на экран и освободили память. Однако, контролировать корректность выделения/освобождения памяти вручную очень сложно. Например, если твоя функция должна завершать выполнение не в одной точке, а в разных (скажем, в случае каких-то ошибок). Поэтому в С++ повсеместно используется идиома RAII. Частным случаем RAII-класса является std::string . С ним просто работать проще.
std::string str; std::getline(std::cin, str); std::cout Все вопросы по выделению, освобождению памяти компилятор берет на себя. 20.02.2018 в 11:50 #4445Что касается динамического массива Динамический массив строк работает точно также как для любых других элементов. Не будет никакой разницы в этих случаях:
string* strs_1; char** strs_2; int* ints;Просто в одном случае тип элемента массива string , в другом – char* , в третьем – int . Динамический массив – это структура данных, размер которой на этапе компиляции не известен (оттого и “динамический”). Когда я выделял выше память под char* с помощью new – я использовал динамический массив символов. Ведь на этапе компиляции не было известно сколько символов захочет ввести пользователь. Если уж тебе очень хочется создать динамический массив строк типа char* – то так и быть:
// переменные strings_count и len ты инициализируешь сам char** strs = new char*[strings_count]; for (int i = 0; i < strings_count; ++i) < strs[i] = new char[len]; std::cin.getline(str, len); >for (int i = 0; i < strings_count; ++i) < delete[] strs[i]; >delete[] strs;Когда освобождаешь память – то надо не забыть сделать это как для каждой строки, так и для массива. На каждый new должен быть обязательно вызван delete . Иначе память “утечет” и однажды кончится (программа “упадет”). Увеличить массив нельзя. По крайней мере эффективно. С помощью new ты получил кусочек памяти, в ней работаешь. Кусочек этот внутри не имеет “разрывов” – именно поэтому ты можешь эффективно за O(1) обращаться к произвольному элементу массива. Никто не может тебе гарантировать, что за этим кусочком есть неиспользуемая область нужного тебе (ты хочешь увеличить размер массива) размера. Что касается realloc то он сработает не всегда (только если есть за твоей областью памяти нужный свободный кусок). Использовать realloc можно только с malloc (с new работать не будет). Вообще, если надо увеличить массив – то в общем случае придется создать новый (большего размера), скопировать в него старый, освободить память из под старого. Это не эффективно. За вас это может сделать std::vector (у него есть метод push_back для добавления в конец, но работает он тоже за O(n) , т.е. медленно). Пример, рассмотренный выше мог бы быть так переписан:
std::vector strs; for (int i = 0; i
Освобождать память опять же не надо, т.к. std::vector – это тоже RAII класс. Если вам часто надо “изменять размер массива” – то массив вообще использовать не стоит. Для этого больше подходят связные списки. В стандартной библиотеке – это класс std::list :
std::list strs; for (int i = 0; i
Код от вектора не сильно отличается, но работать будет гораздо быстрее. Дело в том, что связные списки не требуют выделения цельного куска памяти и когда надо “увеличить размер” они выделяют память в другом месте только под один элемент данных и указателями привязывает его к старому списку. Однако, по этой же причине вы не сможете работать с элементами такого списка по индексу.
Как создать динамический массив строк
"В отличие от классического массива, может хранить null;" ♂️♂️♂️ С каких это пор классические массивы не могут хранить null .
Виктор Уровень 20 Expert
26 сентября 2020Спасибо за статью, законспектировал из забрал к себе на канал. -- Канал в телеге про Java и Android, в котором есть книги для скачивания, статьи, видеоуроки, чат для обмена знаниями и моральной поддержки : ) Давайте учиться вместе: @LetsCodeIt p. s. Мой личный телеграм канал вкатывальщика в прогерство: @SefoNotasi
Сообщество
JavaRush — это интерактивный онлайн-курс по изучению Java-программирования c нуля. Он содержит 1200 практических задач с проверкой решения в один клик, необходимый минимум теории по основам Java и мотивирующие фишки, которые помогут пройти курс до конца: игры, опросы, интересные проекты и статьи об эффективном обучении и карьере Java‑девелопера.
Подписывайтесь
Язык интерфейса
"Программистами не рождаются" © 2024 JavaRush
Скачивайте наши приложения
"Программистами не рождаются" © 2024 JavaRushЭтот веб-сайт использует данные cookie, чтобы настроить персонально под вас работу сервиса. Используя веб-сайт, вы даете согласие на применение данных cookie. Больше подробностей — в нашем Пользовательском соглашении.
Динамические массивы
Тип динамического массива конструируется следующим образом:
array of тип элементов (одномерный массив)
array [,] of тип элементов (двумерный массив)
и т.д.Переменная типа динамический массив представляет собой ссылку. Поэтому динамический массив нуждается в инициализации (выделении памяти под элементы).
Выделение памяти под динамический массив
Для выделения памяти под динамический массив используется два способа. Первый способ использует операцию new в стиле вызова конструктора класса:
var
a: array of integer;
b: array [,] of real;
begin
a := new integer[5];
b := new real[4,3];
end.Данный способ хорош тем, что позволяет совместить описание массива и выделение под него памяти:
var
a: array of integer := new integer[5];
b: array [,] of real := new real[4,3];Описание типа можно при этом опускать - тип автовыводится:
Второй способ выделения памяти под динамический массив использует стандартную процедуру SetLength :
Элементы массива при этом заполняются значениями по умолчанию.
Процедура SetLength обладает тем преимуществом, что при ее повторном вызове старое содержимое массива сохраняется.
Инициализация динамического массива
Можно инициализировать динамический массив при выделении под него память операцией new:
Инициализацию динамического массива в момент описания можно проводить в сокращенной форме:
var
a: array of integer := (1,2,3);
b: array [,] of real := ((1,2,3),(4,5,6),(7,8,9),(0,1,2));
c: array of array of integer := ((1,2,3),(4,5),(6,7,8));При этом происходит выделение памяти под указанное справа количество элементов.
Инициализация одномерного массива проще всего осуществляется стандартными функциями Seq. которые выделяют память нужного размера и заполняют массив указанными значениями:
var a := Arr(1,3,5,7,8); // array of integer
var s := Arr('Иванов','Петров','Сидоров'); // array of string
var b := ArrFill(777,5); // b = [777,777,777,777,777]
var r := ArrRandom(10); // заполнение 10 случайными целыми в диапазоне от 0 до 99В таком же стиле можно инициализировать массивы массивов:
var a := Arr(Arr(1,3,5),Arr(7,8),Arr(5,6)); // array of array of integer
Длина динамического массива
Динамический массив помнит свою длину (n-мерный динамический массив помнит длину по каждой размерности). Длина массива (количество элементов в нем) возвращается стандартной функцией Length или свойством Length :
Для многомерных массивов длина по каждой размерности возвращается стандартной функцией Length с двумя параметрами или методом GetLength(i) :
Ввод динамического массива
После выделения памяти ввод динамического массива можно осуществлять традиционно в цикле:
for var i:=0 to a.Length-1 do
read(a[i]);Ввод динамического массива можно осуществлять с помощью стандартной функции ReadSeqInteger:
var a := ReadSeqInteger(10);
При этом под динамический массив выделяется память нужного размера.
Вывод динамического массива
Процедура write выводит динамический массив, заключая элементы в квадратные скобки и разделяя их запятыми:
var a := Arr(1,3,5,7,9);
writeln(a); // [1,3,5,7,9]n-мерный динамический массив выводится так, что каждая размерность заключается в квадратные скобки:.
var m := new integer[3,3] ((1,2,3),(4,5,6),(7,8,9));
writeln(m); // [[1,2,3],[4,5,6],[7,8,9]]Динамический массив можно выводить также методом расширения Print или Println:
При этом элементы по умолчанию разделяются пробелами, но можно это изменить, задав параметр Print, являющийся разделителем элементов. Например:
выводит каждый элемент на отдельной строке.
Массивы массивов
Если объявлен массив массивов
var с: array of array of integer;
то его инициализацию можно провести только с помощью SetLength :
SetLength(с,5);
for i := 0 to 4 do
SetLength(c[i],3);Для инициализации такого массива с помощью new следует ввести имя типа для array of integer :
type IntArray = array of integer;
var с: array of IntArray;
.
c := new IntArray[5];
for i := 0 to 4 do
c[i] := new integer[3];Инициализацию массива массивов можно также проводить в сокращенной форме:
var
c: array of array of integer := ((1,2,3),(4,5),(6,7,8));Присваивание динамических массивов
Динамические массивы одного типа можно присваивать друг другу, при этом обе переменные-ссылки будут указывать на одну память:
var a1: array of integer;
var a2: array of integer;
a1 := a2;Следует обратить внимание, что для динамических массивов принята структурная эквивалентность типов: можно присваивать друг другу и передавать в качестве параметров подпрограмм динамические массивы, совпадающие по структуре.
Чтобы одному динамическому массиву присвоить копию другого массива, следует воспользоваться стандартной функцией Copy :
Передача динамического массива в подпрограмму
Динамический массив обычно передается в подпрограмму по значению, т.к. сама переменная уже является ссылкой:
procedure Squares(a: array of integer);
begin
for var i:=0 to a.Length-1 do
a[i] := Sqr(a[i]);
end;begin
var a := Arr(1,3,5,7,9);
Squares(a);
end.Динамический массив передается по ссылке только в одном случае: если он создается или пересоздается внутри подпрограммы. В частности, это необходимо делать если для динамического масива внутри подпрограммы вызывается SetLength:
procedure Add(var a: array of integer; x: integer);
begin
SetLength(a,a.Length+1);
a[a.Length-1] := x;
end;begin
var a := Arr(1,3,5,7,9);
Add(a,666);
writeln(a);
end.