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

Как записать числа в массив c

  • автор:

Записать в массив число

Случайное число записать в массив
Задание 1: Запись в файл данных 1. Запросить у пользователя число N 2. Сгенерировать N чисел.

Записать число в массив по цифре
Как запихнуть число в массив по цифре? к примеру 127 по числам 1.2.7

Число разделить на 5 и остаток записать в массив
Нужно число делить на 5 и остачу записывать в массив(начиная с первой остачи). Пример 121:5-1 4 4.

Записать число типа int в массив char -ов так, как оно представляется в памяти
Здравствуйте, моя цель — записать переменную какого-либо типа в массив char-ов (строку) так, как.

Как записать числа в массив c

В этой статье вы научитесь работать с массивами: объявлять, инициализировать и получать доступ к элементам

Иллюстрация

Объявление массива в C/C++

В программировании часто встречается задача обработки множества экземпляров однотипных данных. Представьте себе ситуацию: мы провели опрос 100 человек и узнали их возраст. Чтобы сохранить собранные данные, вы можете создать целочисленный массив, содержащий 100 элементов:

// массив из 100 целых чисел int ages[100]; // массив из 100 целых неотрицательных чисел unsigned ages[100]; // массив из 20 чисел с плавающей точкой // (вы можете использовать константу, известную при компиляции) constexpr unsigned ARRAY_SIZE = 20; float rotations[ARRAY_SIZE]; // общий синтаксис DataType variableName[ARRAY_SIZE]; 

В C++ массивы статичны: вы не сможете изменить размер или тип элементов после объявления.

Доступ к элементам массива

Вы можете получать доступ к элементам массива, используя индексы и оператор [] . Допустим, вы объявили массив marks , как показано ниже. К первому элементу можно обратиться выражением marks[0] , ко второму — выражением marks[1] , и так далее. Доступ всегда начинается с единицы, а индекс последнего элемента на единицу меньше размера массива.

void example()  // Объявляем массив оценок int marks[5]; // Заполняем массив по элементам. marks[0] = 19; marks[1] = 10; marks[2] = 8; marks[3] = 17; marks[4] = 9; > 

Иллюстрация

Инициализация массива при объявлении

Можно инициализировать массив при объявлении. Для этого надо указать в списке столько значений, сколько вмещает массив, либо одно значение 0, чтобы заполнить массив нулями:

// Объявляем массив размера 5 и инициализируем. int marks[5] =  19, 10, 8, 17, 9 >; // Объявляем массив без указания размера, // размер будет определён из списка инициализациии. int marks[] =  19, 10, 8, 17, 9 >; // Объявляем массив размера 10 и заполняем нулями. int ages[10] =  0 >; 

Обход элементов массива в цикле

Узнать число элементов в массиве можно функцией std::size. Обойти можно, используя цикл по индексам либо range-based for:

#include int main()  int ages[] =  17, 18, 29, 30, 16, 27, 22 >; // цикл по индексам массива, // специальный тип size_t - это беззнаковое целое, // разрядность которого совпадает с разрядностью платформы // (4 байта на 32-битных машинах и 8 байт на 64 битных) for (size_t i = 0; i  std::size(ages); ++i)  const int age = ages[i]; std::cout  <"age #"  <i  <" is "  <age  <std::endl; > // цикл по всем элементам массива, // эта конструкция известна как range-based for. int agesSum = 0; for (int age : ages)  agesSum += age; > std::cout  <"ages sum is "  <agesSum  <std::endl; // ещё одна фишка: цикл в стиле итераторов auto end = std::end(ages); int minAge = ages[0]; for (auto it = std::begin(ages); it != end; ++it)  // если этот элемент меньше минимального, обновляем минимальный возраст. const int age = *it; if (age  minAge)  minAge = age; > > std::cout  <"smallest age is "  <minAge  <std::endl; > 

Неопределённое поведение: выход за границы (out of bounds)

Выход за пределы массива является неопределённым поведением (англ. undefined behavior). Нет гарантий, как поведёт себя программа в этом случае. Высока вероятность, что вы испортите память других переменных, но эффект может различаться в разных режимах компиляции:

#include int main()  // Индексы элементов: 0, 1, 2 int ages[] = 1, 2, 3>; // Неопределённое поведение! Запрос элемента с индексом 3 в массиве, // где такого индекса нет. std::cout  <ages[3]  <std::cout; > 

Передача массива как параметра функции

Массив в стиле языка C хранит только указатель на начало и не хранит свой размер, что и создаёт сложность в передаче в функцию. Размер массива известен во время компиляции, но не известен во время выполнения. Поэтому передать размер можно несколькими не очень очевидными путями:

#include // Передаём указатель на начало массива и размер массива // Тип size_t - это целочисленный тип, число байтов которого равно числу байт в указателях, // то есть 4 байта на 32-битных платформах и 8 байт на 64-битных. void printArrayV1(int* values, size_t size)  for (size_t i = 0; i  size; ++i)  std::cout  <values[i]  <std::endl; > > // Передаём ссылку на массив известного размера constexpr size_t AGES_COUNT = 3; void printArrayV2(int (&values)[AGES_COUNT])  for (size_t i = 0; i  std::size(values); ++i)  std::cout  <values[i]  <std::endl; > > // Третий способ - использовать gsl::span, // но ввиду сложности этого пути мы не станем его описывать. int main()  // Индексы элементов: 0, 1, 2 int ages[] = 1, 2, 3>; printArrayV1(ages, std::size(ages)); printArrayV2(ages); > 

Динамически изменяемый массив

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

Так мог бы выглядеть имитация динамического массива:

#include #include #include // Псевдо-динамический массив, вмещает не больше 100 элементов struct DynamicArray  static constexpr size_t MAX_SIZE = 100; size_t size = 0; int data[MAX_SIZE] =  0 >; >; // Добавляет элемент в конец массива void array_push(DynamicArray& array, int value)  // Если условие не соблюдатся, assert вызовет аварийное // завершение программы (но только в отладочной сборке). assert(array.size  DynamicArray::MAX_SIZE); // Поместим значение по индексу [size], после последнего элемента array.data[array.size] = value; // Увеличим размер на единицу ++array.size; > void array_print(const DynamicArray& array)  std::cout  <"; for (size_t i = 0; i  array.size; ++i)  std::cout  <array.data[i]; // Если следующий элемент существует, выводим запятую if (i + 1  array.size)  std::cout  <", "; > > std::cout  <">"  <std::endl; > // Программа создаст массив, заполнит его и выведет содержимое: [10, 3, 7] int main()  DynamicArray ages; array_push(ages, 10); array_push(ages, 3); array_push(ages, 7); array_print(ages); > 

Класс std::vector

Стандартная библиотека C++ содержит шаблонный класс vector, который работает как динамический массив произвольного размера. Размер может расти до тех пор, пока у операционной системы есть область памяти подходящего размера (вплоть до нескольких гигабайт).

Класс является шаблонным, то есть при объявлении переменной потребуется параметризовать шаблон класса vector типом элемента:

#include int main()  std::vectorint> ages =  10, 3, 7 >; > 

Использование вектора похоже на использование массива:

  • работает запрос элемента ages[index] , причём индексация так же начинается с нуля
  • при выходе за границы динамического массива так же возникает неопределённое поведение (англ. undefined behavior)
  • работает перебор элементов с помощью индексов, range-based for или итераторов
  • есть метод size для получения размера: ages.size()
#include #include // Печатает содержимое динамического массива чисел // В отличии от статичного массива, объект класса vector легко передать как параметр. void print(const std::vectorint>& values)  std::cout  <"; for (size_t i = 0; i  values.size(); ++i)  std::cout  <values[i]; // Если следующий элемент существует, выводим запятую if (i + 1  values.size())  std::cout  <", "; > > std::cout  <">"  <std::endl; > int main()  std::vectorint> ages =  10, 3, 7 >; print(ages); > 

Добавление элементов в конец массива

Для добавления существует два метода: push_back и emplace_back

  • push_back получает значение элемента и добавляет в конец
  • emplace_back работает сложнее: он получает параметры, необходимые конструктору элемента, и конструирует его прямо в конце массива

Вы можете практически всегда использовать push_back. Метод pop_back можно использовать для удаления элемента:

#include #include int main()  // эквивалентно инициализации ages = < 10, 3, 7 >. std::vectorint> ages; ages.push_back(10); ages.push_back(3); ages.push_back(7); // убираем последний элемент ages.pop_back(); > 

В документации std::vector можно прочитать о других методах.

Перемещение элементов в памяти при изменении массива

Динамический массив использует для хранения элементов динамическую память (так же известную как “куча”, англ. heap). При добавлении большого числа элементов динамический массив несколько раз перераспределяет память, поскольку выделенной ранее линейной области памяти уже не хватает для хранения всех элементов. Обычно при нехватке памяти под очередной элемент vector запрашивает новую область памяти в 1,5-2 раза больше предыдущей, перемещает в неё уже существующие элементы и добавляет в конец новый, а затем освобождает старую область памяти.

Если не сообразили, как это происходит, взгляните на картинку:

Иллюстрация

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

Метод erase для удаления элементов из середины

Метод erase класса vector получает итератор и уничтожает элемент, на который итератор указывает:

#include #include // Печатает содержимое динамического массива чисел void print(const std::vectorint>& values)  std::cout  <"; for (size_t i = 0; i  values.size(); ++i)  std::cout  <values[i]; // Если следующий элемент существует, выводим запятую if (i + 1  values.size())  std::cout  <", "; > > std::cout  <">"  <std::endl; > int main()  // эквивалентно инициализации ages = < 10, 3, 7 >. std::vectorint> ages =  10, 3, 7 >; // удаляем элемент с индексом 0, остаётся ages.erase(ages.begin()); // удаляем элемент с индексом 1, остаётся ages.erase(ages.begin() + 1); print(ages); > 

Последствия перемещения элементов: ошибка в простом цикле с erase

Использование итератора, ссылки или указателя на элемент после перераспределения памяти в массиве является неопределённым поведением: скорее всего произойдёт падение программы либо будет пропущено несколько элементов коллекции. Это показано в примере ниже:

#include #include // ! КОД С НЕОПРЕДЕЛЁННЫМ ПОВЕДЕНИЕМ ! // После вызова erase итератор it невалиден и не должен использоваться. void eraseNegativeAndPrint(std::vectorint> &ages)  for (auto it = ages.begin(); it != ages.end(); ++it)  if (*it  0)  ages.erase(it); > else  std::cout  <*it  <" "; > > std::cout  <std::endl; > int main()  // эквивалентно инициализации ages = < 10, 3, 7 >. std::vectorint> ages =  10, -33, 23, -18, 7, 38, 99 >; eraseNegativeAndPrint(ages); > 

Если вы запустите этот код, вы можете увидеть что угодно. Скорее всего программа выведет 10 38 99 , хотя должна вывести 10 23 7 38 99 по замыслу автора.

Для решения этой проблемы метод erase возвращает новый, валидный итератор на элемент, следующий после удалённого. Если элемент был последним, erase вернёт итератор end. Учитывая это, мы можем исправить код, чтобы новое значение it либо получалось из erase, либо получалось путём инкремента:

#include #include void eraseNegativeAndPrint(std::vectorint> &ages)  for (auto it = ages.begin(); it != ages.end();)  if (*it  0)  it = ages.erase(it); > else  std::cout  <*it  <" "; ++it; > > std::cout  <std::endl; > int main()  // эквивалентно инициализации ages = < 10, 3, 7 >. std::vectorint> ages =  10, -33, 23, -18, 7, 38, 99 >; eraseNegativeAndPrint(ages); > 

Программа корректно напечатает 10 23 7 38 99 .

Идиома remove_if + erase

В C++ есть замечательная библиотека алгоритмов . В данном случае алгоритмом называют шаблон функции, способный заменить цикл в какой-то одной узкой задаче. Например, remove_if перемещает элементы, соответствующие условию, в конец массива (в “удалённую” зону), и возвращает итератор на начала “удалённой” зоны. Затем вызовом erase можно уничтожить элементы из этой зоны.

#include #include #include bool isNegative(int value)  return (value  0); > void eraseNegativeAndPrint(std::vectorint> &ages)  // Алгоритм remove_if принимает два итератора и функцию, которая решает, // надо ли удалять элемент. auto newEnd = std::remove_if(ages.begin(), ages.end(), isNegative); // У метода erase есть версия, принимающая два итератора: // она удаляет все элементы от первого до второго, // включая первый и не включая второй. ages.erase(newEnd, ages.end()); for (const int age : ages)  std::cout  <age  <" "; > > int main()  // эквивалентно инициализации ages = < 10, 3, 7 >. std::vectorint> ages =  10, -33, 23, -18, 7, 38, 99 >; eraseNegativeAndPrint(ages); > 

Функция корректно напечатает 10 23 7 38 99 .

Для дополнительного чтения

  • О выборе структур данных для начинающих
  • Алгоритмы STL

Как перевести число в массив цифр на Си?

Если и это не то, что вам нужно — поясните тогда понятнее, что вам надо.

Отслеживать
ответ дан 26 июл 2017 в 7:45
218k 15 15 золотых знаков 117 117 серебряных знаков 229 229 бронзовых знаков
Второй вариант может быть из первого получен путём for (i = 0; i < 20; i++) digs[i] -= '0'; 26 июл 2017 в 18:33 @0andriy Может, только тогда это не int , а еще у вас ряд элементов окажется равен -48. 26 июл 2017 в 19:17

Какой смысл в int для цифр? Во втором вы правы, надо добавить проверку на \0. Всяко быстрее, чем деления.

27 июл 2017 в 7:25

@0andriy Никак не соображу, а как получить строку — как ее делает sprintf — без деления? Если не трудно, подскажите алгоритм.

27 июл 2017 в 10:09
@0andriy Спасибо!
29 июл 2017 в 12:48

  • c
  • массивы
    Важное на Мете
Связанные
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.10.27.43697

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Работа с массивами в языке Си

На этой странице относительно подробно рассказывается о статических и динамических массивах. Краткое изложение основных моментов и описание методов поиска ошибок доступны при нажатии на кнопки выше. Двумерные массивы описаны на этой странице.

Массив – это линейно упорядоченная совокупность однотипных элементов. Массив определяется типом элементов (int, double, . ) и длиной. Доступ к элементам осуществляется по индексу – порядковому номеру элемента массива. Логически первый элемент массива имеет индекс ноль. В языке Си существуют статические массивы, число элементов в которых должно быть известно в момент компиляции программы, и динамические массивы, размер которых задается в процессе выполнения программы, то есть может зависеть от входных данных. Эти два типа отличаются только методом создания массива, поэтому сначала рассмотрим статические массивы.

Статические массивы

Способы объявления статических массивов

Объявление статического массива отличается от объявления обычной переменной только указанием количества элементов массива. Например, следующее объявление означает, что именем points называется массив из 100 действительных чисел.

double points[100];

В некотором смысле можно считать, что такое объявление переменной points создает 100 переменных, которые называются points[0], points[1], . points[99]. Плюс к этому, «имена» этих переменных можно вычислять: points[1], points[0+1] или points[k-1] имеют одно значение (если k=2).

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

double points[100]; int students[100];

то в дальнейшем, если возникнет необходимость увеличить один из массивов, будет сложно отличить одну константу от другой. Особенно это верно при обработке элементов массива (см. ниже). Правильным считается использование директив препроцессора для присвоения константам «говорящих» имен. Например:

#define NPOINTS 100 #define NSTUDENTS 100 . double points[NPOINTS]; int students[NSTUDENTS];

Объявление массива может быть совмещено с присвоением значений его элементам. Например,

double points[] = ;

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

Работа с элементами массива

Для доступа к элементу массива достаточно знать его имя и порядковый номер элемента. В языке Си элементы массива индексируются начиная с нуля, то есть в массиве из двух элементов корректными являются индексы 0 и 1. Если массив имеет имя array, то его k -й элемент записывается как array[k] . Это выражение может использоваться как для получения значения элемента массива, так и для его изменения, если оно стоит в левой части оператора присваивания. Рассмотрим для примера следующую программу.

#define NPOINTS 100 int main() < double points[NPOINTS]; int k; points[0] = 0.1; for(k=1; k < NPOINTS; k++) < points[k] = 0.1 + points[k-1]; >return 0; >

Эта программа заполняет массив действительных чисел значениями 0, 0.1, 0.2 и так далее. Отметим, что макропеременная NPOINTS используется как при объявлении массива, так и в качестве верхней границы цикла по всем его элементам. Если размер массива нужно будет изменить, то достаточно исправить одну строчку в программе (#define).

Пример работы с массивом, который задан с начальными значениями:

int main() < double points[] = ; int k; int npoints = sizeof(points)/sizeof(points[0]); for(k=0; k < npoints; k++) < printf("points[%d] = %lf\n", k, points[k]); >return 0; > 

Типичная ошибка при работе с массивами состоит в указании неправильного индекса. Если в приведенной выше программе переменная цикла k будет пробегать значения от 0 до npoints включительно, то поведение программы, вообще говоря, может быть любым. Наиболее вероятным поведением является вывод на экран какого-то значения, но может возникнуть и критическая ошибка, которая приведет к аварийной остановке программы.

Представление массива в памяти и адресная арифметика

В памяти ЭВМ элементы массива записаны последовательно без пропусков. Имя массива является указателем на его начальный элемент (с индексом 0). Поскольку в массиве все элементы имеют одинаковый тип, то зная адрес начала массива (A), размер одного элемента (size) и индекс k можно вычислить адрес размещения k-ого элемента: A + k*size. Если требуется получить значение k-ого элемента массива, то достаточно выполнить одно умножение (k*size), одно сложение (A + k*size) и загрузить значение из памяти по только что вычисленному адресу. Таким образом, обращение к элементу массива очень эффективно и сложность этой операции не зависит от величины индекса k: получение (или изменение) значения нулевого элемента столь же эффективно, как и миллионного.

Хорошо, адрес начала массива мы знаем — это его имя, индекс нам известен, но как узнать size (размер одного элемента)? Чуть ниже мы узнаем как это сделать, но для работы с указателями на элементы массива это не требуется! В языке Си к указателям можно прибавлять целые числа. Например, если есть указатель double *a; , то значением выражения a+9 будет адрес десятого (еще раз вспомним, что массивы индексируются с нуля!) элемента массива, который начинается с адреса a . Компилятор сам понимает, что a является указателем на double и прибавляет нужное значение.

Обратной стороной последовательно хранения элементов в памяти является сложность вставки нового значения с сохранением порядка следования элементов. Например, если в массив нужно добавить новое значение по индексу 0, то чтобы «освободить» место все элементы массива придется сдвинуть на одну позицию. Ясно, что сложность этой операции зависит от длины массива. Чем больше длина, тем дольше выполняется это действие.

Передача массива в функцию

Функция может получать на вход массив. В действительности в функцию передается адрес начала массива и его длина. Прототип функции может быть оформлен либо так:

int print_array(double x[], int len);
int print_array(double *x, int len);

Эти варианты являются эквивалентными. Некоторые программисты предпочитают первый (квадратные скобки показывают, что формальный параметр функции является массивом), другие — второй (имя массива является указателем на нулевой элемент). Естественно, что функция может иметь и другие параметры, в том числе, другие массивы. Это только пример.

Рассмотрим возможную реализацию функции распечатывания массива.

#include int print_array(double x[], int len) < int k; for(k = 0; k < len; k++) < printf("x[%d] = %lf\n", k, x[k]); >return 0; >

При вызове функции в качестве аргумента нужно передавать имя массива и его длину.

int main() < double points[] = ; int npoints = sizeof(points)/sizeof(points[0]); print_array(points, npoints); return 0; >

Внимание! Если функция print_array изменит значение элемента массива x (например, в цикле будет написано x[k]=0; ), то изменятся значения и в массиве points функции main. Элементы массива при вызове функций не копируются! Функция получает на вход адрес памяти, где записаны элементы массива. Эта память «общая» для вызывающей и вызываемой функции.

Динамические массивы: malloc и free

Статические массивы имеют одно существенное ограничение: размер массива должен быть известен в момент компиляции программы. В большинстве задач размер данных становится известным только в момент выполнения программы. Например, вы написали программу для обработки списка друзей или подписчиков в социальной сети. У одного пользователя друзей мало, а у другого — очень много. Какое значение выбрать для длины массива друзей? 200? 1000? Миллион? Если константа будет очень большой, чтобы «заведомо» (посмотрите как росло число пользователей Интернет) устраивать всех пользователей, то для подавляющего числа пользователей это приведет к излишним затратам памяти. Захотите ли Вы поставить на свой телефон программу, которая при запуске займет всю его память с сообщением: «А вдруг у тебя миллион друзей. Нет? Всего 12?! Неплохо, прямо как у Oушена! А y Трампа миллион. «? [Друзей не должно и не может быть так много, но это к делу не относится.] Чтобы избежать таких ситуаций нужно уметь выделять минимально необходимое количество памяти.

  • выделение памяти под массив;
  • освобождение памяти, когда она больше не требуется.

Стандартная библиотека языка Си содержит несколько функций для работы с динамической памятью. Нам понадобятся две: malloc (memory allocation — выделение памяти) и free (освобождение). Для использования этих удивительных функций нужно в программе подключить заголовочный файл . Пример программы приведен ниже. Сначала посмотрим, что делают эти функции.

malloc: динамическое выделение памяти

Прототип: void *malloc(size_t size); Параметры: size — беззнаковое целое число, размер запрашиваемой памяти в байтах. Возвращает: Адрес начала выделенной памяти или NULL, если не удалось выделить память. Функция malloc возвращает указатель типа void * — это «абстрактный» указатель на память, который может быть приведен к указателю на любой тип. Функция malloc не может сразу возвращать указатель нужного типа, так как она используется для создания разных массивов, а в прототипе нужно указать конкретный тип возвращаемого значения.

Для выделения памяти под массив из n элементов типа T, где в T могут быть стандартные типы int , double и т.п., необходимо знать размер значения T в байтах. Для определения этой величины в языке Си есть специальный оператор sizeof , который в момент компиляции программы вычисляет нужное значение. Например, массив из n целых чисел будет занимать n*sizeof(int) байт памяти.

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

int length; int *points; // . получили значение length (длина массива) points = (int *)malloc(length * sizeof(int));

Если нужен другой тип данных, допустим double , то int заменяется на нужное имя ( double ) в трех местах (кроме первой строки, так как длина массива всегда является целым числом).

free: освобождение памяти

Функция free позволяет освободить область памяти, которая ранее была выделена программе при вызове malloc .

Прототип void free(void *ptr); Параметры: ptr — указатель, который был получен в результат вызова malloc.

В качестве аргумента функции free может использоваться только тот адрес, который был получен в результате вызова malloc. Нельзя создать статический массив и «освободить» его функцией free. Адрес может быть освобожден только один раз. Если два раза подряд вызвать функцию free с одним и тем же аргументом, то это приведет к аварийному завершению программы.

Пример программы с динамическим массивом

В качестве иллюстрации описанных методов рассмотрим программу, которая динамически выделяет память под массив и считывает его.

#include #include int main() < int npoints; double *points; int k; scanf("%d", &npoints); /* npoints получает значение в момент выполнения программы */ points = (double *)malloc(npoints*sizeof(double)); /* Выдели память для хранения npoints элементов, каждый размера sizeof(double) */ if(points == NULL) < printf("Произошла ошибка. Запросили слишком много памяти??\n"); return -1; >/* Считываем данные с использованием адресной арифметики */ k = 0; while(k < npoints && scanf("%lf", points+k) == 1) < k++; >/* Работаем с points как с обычным массивом */ /* Например, вызываем функцию print_array(points, npoints) */ free(points); /* Освободили память */ return 0; >

Функции, которые возвращают массив

Иногда бывает удобно сделать функцию, которая возвращает динамически созданный массив. Примером может служить функция считывания массива из файла. Такая функция может получать на вход файловую переменную ( FILE * ) и должна вернуть в вызывающую функцию массив значений. Например, массив действительнах чисел. Попробуем ее реализовать.

Во-первых, нужно понять, какой прототип должна иметь такая функция. Она должна вернуть два значения: адрес выделенной памяти и длину массива. Как мы уже знаем, несколько значений можно вернуть используя указатели. Длина массива имеет тип int . Значит параметр функции будет иметь тип int * (адрес, по которому нужно записать значение). Массив — это адрес нулевого элемента, то есть double * . Значит параметр будет иметь тип double ** — «указатель на указатель». Мы должны передать адрес (одна звездочка), по которому нужно записать результат вызова malloc, который имеет тип double * . В результате получаем следующий прототип:

int read_array(FILE *input, double **array, int *length);

Собственно возвращаемое значение функции ( int ) может быть кодом ошибки. Если функция вернет 0, то это означает успешное выполнение. Любое ненулевое значение означает ошибку.

Теперь можно рассмотреть структуру тела функции (для наглядности в приведенном ниже коде отсутствуют проверки успешности считывания и корректности данных).

int read_array(FILE *input, double **array, int *length) < double *arr; int arr_length, k; /* Считываем массив: сначала длину, потом элементы */ fscanf("%d", &arr_length); arr = (double *)malloc(arr_length * sizeof(double)); for(k = 0; k < arr_length; k++) fscanf("%lf", arr + k); /* Копируем результат по заданным адресам */ *length = arr_length; *array = arr; return 0; >

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

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