Сайт о телевидении

Сайт о телевидении

» » Функция создания массива c. Программирование на языке Си: Использование массивов данных в Си. Указатели

Функция создания массива c. Программирование на языке Си: Использование массивов данных в Си. Указатели

Массивы чрезвычайно важная тема в C++. В программах они используются очень часто и разобраться в этой теме необходимо досконально. Сразу вас обрадую – понять и научиться применять массивы достаточно просто даже начинающему.

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

К примеру, надо хранить порядковые номера строк. Согласитесь – любому станет страшно от мысли, что надо создать пятьсот переменных типа int, каждой дать уникальное имя и присвоить значение от 1-го до 500-та. (мне уже страшно:) В таком случае, массивы нас просто спасут.

Отметим основное и перейдем к практическому примеру:

  • массив в С++ – это совокупность определенного количества однотипных переменных, имеющих одно имя. К примеру, int array ; . Эта запись означает, что мы объявили массив с именем array , который содержит в себе 3 переменные типа int ;
  • переменные массива называют элементами;
  • каждый элемент имеет свой уникальный индекс – свой порядковый номер. Используя индекс мы можем обращаться к конкретному элементу. ВАЖНО – индексация элементов массива начинается с 0 . Так в массиве int array первый элемент имеет индекс 0 , а последний – 2 . Чтобы обратиться, например, к нулевому элементу массива и изменить его значение, надо указать имя массива и в квадратных скобках указать индекс элемента – array = 33 .

Рассмотрим пример:

массивы C++

// в этой программе создаем массив с размером size, // с помощью цикла for вносим данные во все ячейки // массива и отображаем их содержимое на экран #include using namespace std; int main() { setlocale(LC_ALL, "rus"); const int SIZE = 10; //объявляем константу int firstArray; //объявляем массив с количеством элементов SIZE for (int i = 0; i < SIZE ; i++) //заполняем и отображаем значения на экран { firstArray[i] = i + 1; // на первом шаге цикла firstArray присвоить 1 (0 + 1) cout << i << "-я ячейка хранит число " << firstArray[i] << endl; } cout << endl; return 0; }

// в этой программе создаем массив с размером size,

// с помощью цикла for вносим данные во все ячейки

// массива и отображаем их содержимое на экран

#include

using namespace std ;

int main ()

setlocale (LC_ALL , "rus" ) ;

const int SIZE = 10 ; //объявляем константу

int firstArray [ SIZE ] ; //объявляем массив с количеством элементов SIZE

for (int i = 0 ; i < SIZE ; i ++ ) //заполняем и отображаем значения на экран

firstArray [ i ] = i + 1 ; // на первом шаге цикла firstArray присвоить 1 (0 + 1)

cout << i << "-я ячейка хранит число " << firstArray [ i ] << endl ;

cout << endl ;

return 0 ;

В строке 12 мы определяем целочисленную константу SIZE , которая будет хранить размер массива (определённое нами, количество его элементов). В строке 13 объявляем массив: указываем тип данных, которые будут храниться в ячейках массива, даем имя и указываем размер в квадратных скобках.

Важно, что в квадратные скобки мы можем записывать только целые константные значения. Надо либо сразу вписать целое число в квадратные скобки при объявлении массива (int firstArray; ), либо определить целочисленную константу до объявления массива и ввести в квадратные скобки имя этой константы (как в нашем примере).

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

Вот представьте, что нам необходимо изменить размер массива с 10 элементов на 200. В этом случае, нам остаётся всего на всего изменить значение целочисленной константы, и таким образом у нас автоматически подставятся новые значения размера и в массив, и во все циклы программы.

Можете попробовать в нашем примере внести любую другую цифру в константу SIZE . И вы увидите, что программа будет прекрасно работать – создаст массив на столько элементов, на сколько вы укажете, внесет данные и отобразит их на экране.

А если массив совсем небольшой, к примеру на 5 элементов, инициализировать его можно сразу при объявлении:

Так элементу с индексом 0 – firstArray – будет присвоено значение 11 , а последнему элементу массива firstArray – значение 1 5 . Есть такая фишка – вы можете не указывать размер массива в квадратных скобках и сделать такую запись:

Предыдущая запись эквивалентна этой. Только во втором случае компилятор автоматически вычислит размер массива, по количеству данных в фигурных скобках.

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

Следует запомнить, что такая инициализация возможна только для заполнения нулями. Если необходимо заполнить элементы массива какими-либо другими числами, лучше применять цикл. В C++11 (стандарт кодирования) при использовании списковой инициализации (инициализации с фигурными скобками) разрешается даже отбросить знак = .

Хочется показать еще один прием инициализации при создании массива. К примеру, для массива из 30-ти элементов нам надо внести значения 33 и 44 только в ячейки с индексом 0 и 1 соответственно, а остальные заполнить нулями. Тогда делаем так:

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

Организовать заполнение массива можно и при помощи оператора cin :

for (int i = 0; i < size; i++) //заполняем и выводим значения на экран { cout << "Введите значение в ячейку №" << i << " :"; cin >> firstArray[i]; }

for (int i = 0 ; i < size ; i ++ ) //заполняем и выводим значения на экран

Пожалуйста, приостановите работу AdBlock на этом сайте.

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

Рис.1 Переменные и массивы. Аналогия с коробками.

На картинке выше изображено три массива:

  • целочисленный массив из 8 элементов с именем arr_int
  • вещественный массив из 11 элементов с именем arr_float
  • символьный массив из 6 элементов с именем arr_char

У массива, как и у переменной, имеются свои имя и тип данных. Кроме того, у массива ещё есть одна дополнительная характеристика – размер массива. Размер массива – количество элементов, которые могут в нём храниться. В нашей аналогии с коробочками это количество коробок.

Обратите внимание!

Нумерация элементов массива начинается с нуля, а не с единицы.

Объявление и инициализация массива

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

Листинг 1.

Int arr_int; double arr_float; float number;

На имя массива накладываются ограничения, аналогичные тем, которые накладываются на имя переменной.

Правило именования массивов

Имя массива – любая последовательность символов, цифр и знака нижнего подчеркивания «_», которая начинается с буквы. Регистр букв важен.

Вот ещё несколько примеров объявления массивов:

Листинг 2.

Int grades, order; double prices;

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

Листинг 3.

Int arr_int = {2, 5, 5, 3, 4}; double arr_float = {1.2, -2.3, 4.5, 3.83, 0.01, -0.12, 44.2, 123.7, 23.44, -3.7, 7};

Если нужно присвоить нулевые значения всем элементам массива, то можно сделать вот так:

Листинг 4.

Double arr = {0};

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

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

Давайте, например, выведем элементы массива из пяти элементов на экран.

Листинг 5.

#include int main(void){ int arr = {2, 4, 3, 5, 5}; printf("%d %d %d %d %d\n",arr, arr, arr, arr, arr); return(0); }

Конечно, если массив будет очень большой, то выводить его поэлементно подобным образом то ещё удовольствие. Да и с маленькими массивами так никто не делает. Лучше и правильнее использовать циклы. Например:

Листинг 6.

#include int main(void){ int arr = {0}; for(int i = 0; i < 100; i = i + 1){ arr[i] = 2*i; } for(int i = 0; i < 100; i = i + 1){ printf("%d\t",arr[i]); } return(0); }

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

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

Листинг 7.

#include #include #include int main(void) { srand(time(NULL)); int count = {0}; int rand_number; for (int i = 0; i < 100000; i = i + 1){ rand_number = rand()%3; count = count + 1; } for(int i = 0; i < 3; i = i + 1){ printf("%d - %d\n", i, count[i]); } return 0; }

Обратите внимание на приём, который используется в этой программе.
В нулевом элементе массива хранится количество выпадений числа 0 , в первом элементе – количество выпадений числа 1 , во втором элементе – числа 2 . То есть само сгенерированное число позволяет определить, к какому элементу массива необходимо добавить единичку. Поэтому необходимость в операторе выбора switch отпадает. Удобно, не так ли?

Последнее обновление: 17.09.2017

Массив представляет набор однотипных данных. Формальное определение массива выглядит следующим образом:

Тип_переменной название_массива [длина_массива]

После типа переменной идет название массива, а затем в квадратных скобках его размер. Например, определим массив из 4 чисел:

Int numbers;

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

Int numbers = {1,2,3,4};

Значения в фигурных скобках еще называют инициализаторами. Если инициализаторов меньше, чем элементов в массиве, то инициализаторы используются для первых элементов. Если в инициализаторов больше, чем элементов в массиве, то при компиляции возникнет ошибка:

Int numbers = {1, 2, 3, 4, 5, 6};

Здесь массив имеет размер 4, однако ему передается 6 значений.

Если размер массива не указан явно, то он выводится из количества инициализаторов:

Int numbers = {1, 2, 3, 4, 5, 6};

В данном случае в массиве есть 6 элементов.

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

Char s1 = {"h", "e", "l", "l", "o"}; char s2 = "world";

Причем во втором случае массив s2 будет иметь не 5 элементов, а 6, поскольку при инициализации строкой в символьный массив автоматически добавляется нулевой символ "\0".

При этом не допускается присвоение одному массиву другого массива:

Int nums1 = {1,2,3,4,5}; int nums2 = nums1; // ошибка nums2 = nums1; // ошибка

После определения массива мы можем обратиться к его отдельным элементам по индексу. Индексы начинаются с нуля, поэтому для обращения к первому элементу необходимо использовать индекс 0. Обратившись к элементу по индексу, мы можем получить его значение, либо изменить его:

#include int main() { int numbers = {1,2,3,4}; int first_number = numbers; std::cout << first_number << std::endl; // 1 numbers = 34; // изменяем элемент std::cout << numbers << std::endl; // 34 return 0; }

Число элементов массива также можно определять через константу:

Const int n = 4; int numbers[n] = {1,2,3,4};

Перебор массивов

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

#include int main() { int numbers = {1,2,3,4}; int size = sizeof(numbers)/sizeof(numbers); for(int i=0; i < size; i++) std::cout << numbers[i] << std::endl; return 0; }

Чтобы пройтись по массиву в цикле, вначале надо найти длину массива. Для нахождения длины применяется оператор sizeof . По сути длина массива равна совокупной длине его элементов. Все элементы представляют один и тот же тип и занимают один и тот же размер в памяти. Поэтому с помощью выражения sizeof(numbers) находим длину всего массива в байтах, а с помощью выражения sizeof(numbers) - длину одного элемента в байтах. Разделив два значения, можно получить количество элементов в массиве. А далее с помощью цикла for перебираем все элементы, пока счетчик i не станет равным длине массива. В итоге на консоль будут выведены все элементы массива:

Но также есть и еще одна форма цикла for , которая предназначена специально для работа с коллекциями, в том числе с массивами. Эта форма имеет следующее формальное определение:

For(тип переменная: коллекция) { инструкции; }

Используем эту форму для перебора массива:

#include int main() { int numbers = {1,2,3,4}; for(int number: numbers) std::cout << number << std::endl; return 0; }

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

Если нам неизвестен тип объектов в массиве, то мы можем использовать спецификатор auto для определения типа:

For(auto number: numbers) std::cout << number << std::endl;

Многомерные массивы

Кроме одномерных массивов в C++ есть многомерные. Элементы таких массивов сами в свою очередь являются массивами, в которых также элементы могут быть массивами. Например, определим двухмерный массив чисел:

Int numbers;

Такой массив состоит из трех элементов, при этом каждый элемент представляет массив из двух элементов. Инициализируем подобный массив:

Int numbers = { {1, 2}, {4, 5}, {7, 8} };

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

1 2
4 5
7 8

Также при инициализации можно опускать фигурные скобки:

Int numbers = { 1, 2, 4, 5, 7, 8 };

Возможна также инициализация не всех элементов, а только некоторых:

Int numbers = { {1, 2}, {}, {7} };

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

Int numbers = { {1, 2}, {3, 4}, {5, 6} }; std::cout << numbers << std::endl; // 3 numbers = 12; // изменение элемента std::cout << numbers << std::endl; // 12

Переберем двухмерный массив:

#include int main() { const int rows = 3, columns = 2; int numbers = { {1, 2}, {3, 4}, {5, 6} }; for(int i=0; i < rows; i++) { for(int j=0; j < columns; j++) { std::cout << numbers[i] [j] << "\t"; } std::cout << std::endl; } return 0; }

Также для перебора элементов многомерного массива можно использовать другую форму цикла for:

#include int main() { const int rows = 3, columns = 2; int numbers = { {1, 2}, {3, 4}, {5, 6} }; for(auto &subnumbers: numbers) { for(int number: subnumbers) { std::cout << number << "\t"; } std::cout << std::endl; } return 0; }

Для перебора массивов, которые входят в массив, применяются ссылки. То есть во внешнем цикле for(auto &subnumbers: numbers) &subnumbers представляет ссылку на подмассив в массиве. Во внутреннем цикле for(int number: subnumbers) из каждого подмассива в subnumbers получаем отдельные его элементы в переменную number и выводим ее значение на консоль.

Объявление массива в Си
Массив (Array) относится к вторичным типам данных. Массив в Си представляет собой коллекция явно определенного размера элементов определенного типа. то есть в отличие от массивов в Ruby массивы в Си являются однотипными (хранят данные только одного типа) и имеют заранее определенную длину (размер).

В Си массивы можно грубо разделить на 2 типа: массив чисел и массив символов. Разумеется, такое деление абсолютно условное ведь символы — это также целые числа. Массивы символов также имеют несколько иной синтаксис. Ниже приведены примеры объявления массивов:

Int arr; int a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; char ch = {"R","u","b","y","D","e","v",".","r","u"}; char ch2 = "сайт";

В первом случае мы объявляем массив целых чисел (4 байта на число) размером в 100 элементов. Точнее мы резервируем память для хранения 100 элементов типа int.

Во втором случае мы определяем массив из 10 целочисленных элементов и сразу же присваиваем элементам массива значения.

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

В последнем случае мы также объявляем массив символов с помощью специального — более лаконичного синтаксиса. Массивы ch и ch2 практически идентичны, но есть одно отличие. Когда для создания массива мы используем синтаксис со строковой константой, то в конец массива символов автоматически добавляется символ \0, при использовании стандартного синтаксиса обявления массива мы должны самостоятельно добавлять \0 в качестве последнего элемента массива символов. Символ \0 (null) используется для идентификации конца строки. О страках мы поговорим более подробно в отдельной статье.

Обращение к элементам массива в Си

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

#include int main() { int arr; int a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; char ch = {"R","u","b","y","D","e","v",".","r","u"} ; char ch2 = "сайт"; printf("%d\n", arr); printf("%c\n", ch); }

Код printf(«%d\n», a); напечатает 2, а не 1 потому, что индексация массивов начинается с 0 и лишнее подтверждение тому строка printf(«%c\n», ch); , которая напечатает символ «R» — нулевой элемент массива ch.

В общем случае объявление массива имеет следующий синтаксис:

тип_данных имя_переменной[<количество_элементов>] = <список, элементов, массива>

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

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

Указатели в Си
Типы данных необходимы для того, чтобы мочь выделить кусок памяти определенного размера для хранения данных и определения того, что это за данные ибо без явного определения непонятно является ли набор нулей и единиц числом, символом или чем-нибудь еще. В этом случае переменная является ссылкой на фрагмент памяти определенного размера и типа, например, int переменная ссылается на определенную область памяти объемом 4 байта, в которой хранится целое число, а char переменная ссылается на область памяти объемом 1 байт в которой хранится символ (код символа).

Чтобы получить адрес на который ссылается переменная мы используем специальный оператор & — оператор адреса (address operator), пример:

#include int main() { int arr; int a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; char ch = {"R","u","b","y","D","e","v",".","r","u"} ; char ch2 = "сайт"; int num = 100500; printf("%p\n", &arr); }

Строка printf(«%p\n», &arr); напечатает 0xbfbbe068. 0xbfbbe068 — шестнадцатеричное представление адреса памяти где хранится число 100500.

Указатели — это переменные специального типа, которые хранят не обыкновенные значения, но их адреса в памяти.

#include int main() { int a, b; b = a = 10; printf("A: %p\n", &a); printf("B: %p\n", &b); }

$ ./program
A: 0xbfe32008
B: 0xbfe3200c

В примере выше мы присваиваем переменным a и b одинаковое значение — число 10, но переменные a и b ссылаются на две разные области памяти, то есть мы сохраняем в памяти число 10 два раза. Если мы изменим значение переменной b, то оно это не отразится на переменной a и наоборот. Это отличается от того, как мы работаем с переменными в Ruby, где переменные — это ссылки на объекты хранимые в памяти, и при присваивании в стиле a = b = 10 мы получаем один объект — число 10 и две ссылки на него.

#include int main() { int a = 10; int * b = &a; printf("A:\n\taddress: %p\n\tvalue: %d\n",&a, a); printf("B:\n\taddress: %p\n\tvalue: %d\n",b, *b); }

Результат выполнения:

$ ./program
A:
address: 0xbfed0fa8
value: 10
B:
address: 0xbfed0fa8
value: 10

Указатели и массивы

На самом деле в Си нет массивов в привычном для многих людей понимании. Любой массив в Си — это просто ссылка на нулевой элемент массива. Пример:

#include int main() { int a = {10,20,30}; printf("a-Address:%p\n", &a); printf("a-Address:%p\n", &a); printf("a-Value:%d\n", a); printf("a-Size:%d\n", sizeof(a)); }

Результат:

$ ./program
a-Address:0xbfc029b4
a-Address:0xbfc029b4
a-Value:10
a-Size:12

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

Когда мы запускаем программу, то операционная система предоставляет программе два особых объема памяти — стек (stack) и кучу (heap). В нашей программе используется только стек. Стек хранит значения упорядочено. Когда мы создаем массив, мы на самом деле создаем указатель ну нулевой элемент коллекции элементов и резервируем память для N-количества элементов. В примере выше мы создали коллекцию из 3 элементов типа int, т.е. каждый элемент занимает 4 байта памяти. Когда мы воспользовались функцией sizeof(), которая возвращает размер в байтах переданного ей аргумента, то получили значение 12 т.е. массив занимает 12 байт памяти: 3элемента * 4 байта. Поскольку для хранения элементов коллекции используется стек — элементы сохраняются по порядку, то есть занимают соседние области стека, а это означает, что мы можем перемещаться по коллекции зная позицию элемента и размер коллекции. Пример:

#include int main() { int a = {10,20,30,40,10}, i; for(i = 0; i <= sizeof(a)/sizeof(int); i++) printf("a[%d] has %d in %p\n", i, a[i], &a[i]); }

Результат:

$ ./program
a has 10 in 0xbfbeda88
a has 20 in 0xbfbeda8c
a has 30 in 0xbfbeda90
a has 40 in 0xbfbeda94
a has 10 in 0xbfbeda98
a has 5 in 0xbfbeda9c

Программа напечатала нам информацию о массиве из 5 элементов: номер элемента, значение и адрес в памяти. Обратите внимание на адреса элементов — это то, о чем я вам говорил. Адреса идут подряд и каждый следующий больше предыдущего на 4. В 5 элементе коллекции, которого мы на самом деле не объявляли хранится общее количество элементов коллекции. Самое интересное — это то, что мы можем аналогичным образом использовать и указатели для прохода по массиву. Пример:

#include int main() { int a = {10,20,30,40,10}, i; int * b = a; for(i = 0; i <= sizeof(a)/sizeof(int); i++) printf("a[%d] has %d in %p\n", i, *(b + i), b + i); }

Примечания

1. Обратите внимание на то, что указателю b мы присваиваем не адрес массива a, а само значение переменной a, ведь a это, по сути и есть указатель.

2. Использование квадратных скобой с указанием индексов элементов массива — это такой синтаксический сахар в Си для более удобного и понятного обращения к элементам коллекции.

3. Как я уже говорил, в Си нету традиционных массивов потому, я называю их коллекциями для того, чтобы подчеркнуть эту особенность Си.

4. Адрес 1 элемента массива больше адреса 0 элемента массива на объем памяти выделяемой под хранение элемента данного типа. Мы работаем с элементами типа int, для хранения каждого из которых используется 4 байта. Адрес элемента массива в памяти и вообще любых данных — это адрес первого байта выделяемой под его хранение памяти.

5. Для упрощения понимания представьте, что память компьютера — это огромный кинотеатр, где места пронумерованы от 0 до, скачем 1_073_741_824. У данных типа char задница нормального размера и они помещаются в одном кресле (занимают один байт), а у толстых посетителей типа long double задницы огромные и каждый из них вмещается только на 10 сидениях. Когда у толстых посетителей кинотеатра спрашивают номер их места, они говорят только номер первого кресла, а количество и номера всех остальных кресел можно легко вычислить исходя из комплекции посетителя (типа данных). Массивы можно представить в виде групп однотипных посетителей кинотеатра, например группа худеньких балерин типа char из 10 человек займет 10 мест потому, что char вмещается в одном кресле, а группа любителей пива состоящая из 5 человек типа long int займет 40 байт.

6. У операторов & и * имеется несколько популярных названий, но вы можете называть их хоть Васей и Петей. Главное, что стоит запомнить — это:

& — показывает номер первого занятого посетителем кинотеатра сидения. То есть адрес первого занимаемого байта.

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

На этом статья окончена, но не окончена тема массивов и указателей, а тем более изучения всего языка Си.

Responses

  1. anonymouse says:

    Проверь, действительно ли эти два массива одинаковы:
    char ch = {‘R’,"u’,"b’,"y’,"D’,"e’,"v’,’.’,"r’,"u’};
    char ch2 = «сайт»;
    Во втором случае массив содержит на один элемент больше, /0, который используется как ограничитель при печати, копировании строк и так далее.

  2. admin says:

    На самом деле оба массива содержат символ \0 в качестве 10 элемента, по этому они действительно одинаковы, но о символе \0 я расскажу в отдельной статье посвященной символьным массивам и строкам.

  3. anonymouse says:

    Да, ты оказался прав, я написал тот комментарий до того как сам проверил вот этот код в GCC:
    #include
    #include

    int main(void)
    {
    char ch = {‘R’,"u’,"b’, ‘y’, ‘D’, ‘e’, ‘v’, ‘.’, ‘r’, ‘u’};
    char ch2 = «сайт»;

    printf(«%x\n», ch[ strlen(ch) ]);

    return 0;
    }
    Печатает ноль.

  4. admin says:

    Самое интересно, что если верить спецификации ANSI C, то ты прав ведь там ничего не сказано об автодобавлении нулевого символа в конец массива символов созданного стандартным для массивов способом (и в K&R это в обоих вариантах делается явно). Думаю, это или отличие в С99 или в компиляторе дело, так как производители компиляторов реализуют возможности С99 в основном частично, а некоторые добавляют что-то свое. Теперь понятно, почему выбор компилятора так важен. Нужно будет над этим вопросом попозже поработать и написать статью о различиях компиляторов Си, поддержке ими С99 и различиях между ANSI C и C 99.

  5. admin says:

    Провел расследование, все таки я дезинформировал тебя. В традиционном синтаксисе \0 не добавляется, это просто такое совпадение, что следующим в стеке идет символ \0, но он не относится к массиву символов. Если использовать strlen() то явно видна разница в 1 символ между традиционным синтаксисом создания массива. где символы просто перечисляются и использованием строковой константы. null-символ добавляется автоматически только в конец массива символов созданного при помощи строковой констранты.

  6. andr says:

    Очень много вводящих в заблуждение высказываний. Такими статьями начинающих программистов только портить. :)
    Например, «В 5 элементе коллекции, которого мы на самом деле не объявляли хранится общее количество элементов коллекции.», — вот это невиданные сказки. В языке С нигде не хранится длина массивов. В этом примере происходит выход за пределы массива ‘a’, т.к. для 5-ти элементов массива последний индекс == 4, а ты его индексируешь до 5-ти. Тем самым обращаешься по адресу переменной i, которую компилятор разместил в памяти сразу после массива, поэтому на последнем цикле (когда i == 5) и получаешь в результате 5-ку на выходе.

    «Как я уже говорил, в Си нету традиционных массивов потому, я называю их коллекциями для того, чтобы подчеркнуть эту особенность Си.» — это совсем что-то непонятное. Что такое «традиционные массивы»? Коллекции, кстати, это более широкий термин. Под определение коллекций подходят массивы, списки, матрицы, стеки и даже хеш-таблицы. Зачем вводить неподходящие термины и вводить в заблуждение читателей?

  7. admin says:

    andr спасибо за замечание. Я только недавно начал изучать Си, и это были мои предположения. Си несколько непривычен для меня, вот и получаются такие ошибки. Скоро поправлю.

  8. faustman says:

    Про худеньких балерин и группу любителей пива хорошо сказал!))

  9. Myname says:

    А у меня gcc a, которое, вы говорите, хранит количество элементов, выдает значение 32767.

До сих пор мы работали с простыми типами данных – логический (boolean), целый (integer , word , byte , longint), вещественный (real), символьный (char). Любой алгоритм можно запрограммировать с помощью этих четырех базовых типов. Но для обработки информации о многообразном реальном мире требуются данные, имеющие более сложное строение. Такие сложные конструкции, основанные на простейших скалярных типах, называются структурами. Структура – некоторый составной тип данных, составленный из базовых скалярных. Если структура не изменяет своего строения на протяжении всего выполнения программы, в которой она описана, то такую структуру называют статической.

Массив – однородная совокупность элементов

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

Массивы состоят из ограниченного числа компонент, причем все компоненты массива имеют один и тот же тип, называемый базовым. Структура массива всегда однородна. Массив может состоять из элементов типа integer , real или char , либо других однотипных элементов. Из этого, правда, не следует делать вывод, что компоненты массива могут иметь только скалярный тип.

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

Индекс массива

Номер элемента массива называется индексом . Индекс – это значение порядкового типа, определенного, как тип индекса данного массива. Очень часто это целочисленный тип (integer , word или byte), но может быть и логический и символьный.

Описание массива в Паскале. В языке Паскаль тип массива задается с использованием специального слова array (англ. – массив), и его объявление в программе выглядит следующим образом:

Type < имя _ типа >= array [ I ] of T;

где I – тип индекса массива, T – тип его элементов.

Можно описывать сразу переменные типа массив, т.е. в разделе описания переменных:

Var a,b: array [ I ] of T;

Обычно тип индекса характеризуется некоторым диапазоном значений любого порядкового типа: I 1 .. I n . Например, индексы могут изменяться в диапазоне 1..20 или " a ".." n ".

При этом длину массива Паскаля характеризует выражение:

ord (I n)- ord (I 1)+1.

Вот, например, объявление двух типов: vector в виде массива Паскаля из 10 целых чисел и stroka в виде массива из 256 символов:

Type
Vector=array of integer;
Stroka=array of char;

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

Опишем переменные типа vector и stroka:

Вычисление индекса массива Паскаля

Индекс массива в Паскале не обязательно задавать в явном виде. В качестве индекса массива можно использовать переменную или выражение, соответствующее индексному типу. Иначе говоря, индексы можно вычислять.

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

Пример программы с ошибкой массива Паскаля

Program primer _ error ;
Type
vector=array of word;
var
n: integer;
a: vector;
begin
n:=45;
a:=25;
end .

Хотя данная программа полностью соответствует синтаксису языка, и транслятор «пропустит» ее, на стадии выполнения произойдет ошибка выхода за пределы массива Паскаля. При n =45 выражение n *2=90, компьютер сделает попытку обратиться к элементу массива a , но такого элемента нет, поскольку описан массив размерностью 80.

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

Из всего этого следует сделать вывод: программисту надо быть очень аккуратным при работе с индексами массива.

Основные действия с массивами Паскаля

Как известно, определение типа данных означает ограничение области допустимых значений, внутреннее представление в ЭВМ, а также набор допустимых операций над данными этого типа. Мы определили тип данных как массив Паскаля. Какие же операции определены над этим типом данных? Единственное действие, которое можно выполнять над массивами целиком, причем только при условии, что массивы однотипны, – это присваивание. Если в программе описаны две переменные одного типа, например,

Var
a , b: array of real ;

то можно переменной a присвоить значение переменной b (a:= b). При этом каждому элементу массива a будет присвоено соответствующее значение из массива b . Все остальные действия над массивами Паскаля производятся поэлементно (это важно!) .

Ввод массива Паскаля

Для того чтобы ввести значения элементов массива, необходимо последовательно изменять значение индекса, начиная с первого до последнего, и вводить соответствующий элемент. Для реализации этих действий удобно использовать цикл с заданным числом повторений, т.е. простой арифметический цикл, где параметром цикла будет выступать переменная – индекс массива Паскаля. Значения элементов могут быть введены с клавиатуры или определены с помощью оператора присваивания.

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

Var
A: array of integer ;
Begin
For i:=1 to 10 do
Readln (a[i]); { ввод i- го элемента производится с клавиатуры }

Рассмотрим теперь случай, когда массив Паскаля заполняется автоматически случайными числами, для этого будем использовать функцию random (N).

Пример фрагмента программы заполнения массива Паскаля случайными числами

Var
I: byte ; {переменная I вводится как индекс массива}
Begin
For i:=1 to 10 do
A [ i ]:= random (10); { i -му элементу массива присваивается «случайное» целое число в диапазоне от 0 до 10}

Вывод массива Паскаля

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

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

Var
A: array of integer;
I: byte ; {переменная I вводится как индекс массива}
Begin
For i:=1 to 10 do
Write (a [ i ]," "); {вывод массива осуществляется в строку, после каждого элемента печатается пробел}

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

Пример программы вывода массива Паскаля в столбик

Var
A: array of integer;
I: byte ; {переменная I вводится как индекс массива}
Begin
For i:=1 to 10 do
Writeln ("a[", i,"]=", a[i]); { вывод элементов массива в столбик }

На экране мы увидим, к примеру, следующие значения:

a =2
a =4
a =1 и т.д.

Пример решения задачи с использованием массивов Паскаля

Задача: даны два n -мерных вектора. Найти сумму этих векторов.

Решение задачи:

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

    var a , b: array of integer ;

  • Выходными данными будут элементы результирующего массива, назовем его c . Тип результирующего массива также должен быть целочисленным.
  • Кроме трех массивов нам потребуется переменная – параметр цикла и индекс массива, назовем ее i , а также переменная n для определения количества элементов в каждом массиве.

Ход решения задачи:

  • определим количество элементов (размерность) массивов, введем значение n ;
  • введем массив a ;
  • введем массив b ;
  • в цикле, перебирая значения индекса i от 1 до n , вычислим последовательно значения элементов массива c по формуле:

    c [ i ]= a [ i ]+ b [ i ];

  • выведем на экран полученный массив.

Текст программы:

Пример программы суммирования векторов

Program summa;
Var
a, b, c: array of integer;
I, n: byte;
Begin
Write ("введите размерность массивов:");
Readln(n);
For i:=1 to n do
Readln (a[i]); { ввод массива a}
For i:=1 to n do
Readln (b[i]); { ввод массива b}
For i:=1 to n do
C[i]:=a[i]+b[i]; { вычисление суммы массивов }
For i:=1 to n do
write (c[i]," "); { вывод массива с }
end.