Массивы в языке Си

Язык Си / Массивы в языке Си

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

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

Массив характеризуется следующими основными понятиями:

Элемент массива (значение элемента массива) – значение, хранящееся в определенной ячейке памяти, расположенной в пределах массива, а также адрес этой ячейки памяти.

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

  • адресом элемента - адресом начальной ячейки памяти, в которой расположен этот элемент;
  • индексом элемента (порядковым номером элемента в массиве);
  • значением элемента.

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

Графически расположение массива в памяти компьютера можно представить в виде непрерывной ленты адресов.
Расположение массива в памяти

Представленный на рисунке массив содержит q элементов с индексами от 0 до q-1. Каждый элемент занимает в памяти компьютера k байт, причем расположение элементов в памяти последовательное.

Адреса i-го элемента массива имеет значение

n+k·i

Адрес массива представляет собой адрес начального (нулевого) элемента массива. Для обращения к элементам массива используется порядковый номер (индекс) элемента, начальное значение которого равно 0. Так, если массив содержит q элементов, то индексы элементов массива меняются в пределах от 0 до q-1.

Длина массива – количество байт, отводимое в памяти для хранения всех элементов массива.

ДлинаМассива = РазмерЭлемента * КоличествоЭлементов

Для определения размера элемента массива может использоваться функция

int sizeof(тип);

Например,

sizeof(char) = 1;
sizeof(int) = 4;
sizeof(float) = 4;
sizeof(double) = 8;
Объявление и инициализация массивов

Для объявления массива в языке Си используется следующий синтаксис:

тип имя[размерность]={инициализация};

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

int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9};  // массив a из 10 целых чисел
int a[10] = {0}; // массив a из 10 элементов, инициализированных 0

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

int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

При обращении к элементам массива индекс требуемого элемента указывается в квадратных скобках [].

Пример

#include <stdio.h>
int main() {
  int a[]={5, 4, 3, 2, 1}; // массив a содержит 5 элементов
  printf("%d %d %d %d %d\n",a[0], a[1], a[2], a[3], a[4]);
  getchar();
  return 0;
}

Результат выполнения программы:
Массив из 5 элементов

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

int a[10];

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

#include <stdio.h>
int main() {
  int a[5]; // объявлен массив a  из 5 элементов
  int i;
  // Ввод элементов массива
  for(i=0; i<5; i++)  {
     printf("a[%d] = ", i);
     scanf("%d", &a[i]); // &a[i] - адрес i-го элемента массива
    }
  // Вывод элементов массива
  for(i=0;i<5;i++)  {
      printf("%d ",a[i]); // пробел в формате печати обязателен
    }
  getchar();
  getchar();
  return 0;
}

Результат выполнения программы
Массив

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

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

Общая форма объявления многомерного массива

тип имя[размерность1][размерность2]...[размерностьm];

Элементы многомерного массива располагаются в последовательных ячейках оперативной памяти по возрастанию адресов. В памяти компьютера элементы многомерного массива располагаются подряд, например массив, имеющий 2 строки и 3 столбца,

int a[2][3];

будет расположен в памяти следующим образом

Двумерный массив
Общее количество элементов в приведенном двумерном массиве определится как
КоличествоСтрок * КоличествоСтолбцов = 2 * 3 = 6.
Количество байт памяти, требуемых для размещения массива, определится как
КоличествоЭлементов * РазмерЭлемента = 6 * 4 = 24 байта.

Инициализация многомерных массивов

Значения элементов многомерного массива, как и в одномерном случае, могут быть заданы константными значениями при объявлении, заключенными в фигурные скобки {}. Однако в этом случае указание количества элементов в строках и столбцах должно быть обязательно указано в квадратных скобках [].

Пример

#include <stdio.h>
int main() {
  int a[2][3]={1, 2, 3, 4, 5, 6};
  printf("%d %d %d\n", a[0][0], a[0][1], a[0][2]);
  printf("%d %d %d\n", a[1][0], a[1][1], a[1][2]);
  getchar();
  return 0;
}

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

Пример

#include <stdio.h>
int main() {
  int a[2][3]; // массив из 2 строк и 3 столбцов
  int i, j;
  // Ввод элементов массива
  for(i=0; i<2; i++)  // цикл по строкам
   {
    for(j=0; j<3; j++) // цикл по столбцам
     {
       printf("a[%d][%d] = ", i,j);
      scanf("%d", &a[i][j]);
    }
  }
  // Вывод элементов массива
  for(i=0; i<2; i++)  // цикл по строкам
   {
     for(j=0; j<3; j++) // цикл по столбцам
       {
         printf("%d ", a[i][j]);
       }
     printf("\n"); // перевод на новую строку
   }
  getchar();
  getchar();
  return 0;
}

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

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

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

  • адрес массива,
  • размер массива.

Исключение составляют функции обработки строк, в которые достаточно передать только адрес.

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

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

Пример Дан массив из 10 элементов. Поменять местами наибольший и начальный элементы массива. Для операций поиска максимального элемента и обмена использовать функцию.

#include <stdio.h>
// Функция обмена
void change(int *x, int n) {
// x - указатель на массив (адрес массива)
// n - размер массива
  int i;
  int max, index;
  max = x[0];
  index = 0;
  // Поиск максимального элемента
  for(i=1; i<n; i++)
  {
    if(x[i]>max)
    {
      max= x[i];
      index = i;
     }
  }
// Обмен
  x[index] = x[0];
  x[0] = max;
}
int main() {
  int a[10];
  int i;
  for(i=0; i<10; i++)
  {
   printf("a[%d] = ", i);
   scanf("%d", &a[i]);
  }
  change(a,10);  // вызов функции обмена
  // Вывод элементов массива
  for(i=0; i<10; i++)
  {
    printf("%d ", a[i]);
  }
  getchar();
  getchar();
  return 0;
}

Результат выполнения
Поменять местами наибольший и первый элементы массива

Пример Дан массив размерности n. Вычислить произведение четных элементов

#include <stdio.h>
int func(int *x, int n) { // произведение четных элементов
  int p=1;  // начальное значение произведения
  int i;
  for(i=0;i<n; i++) {
    if(x[i] % 2==0)  // остаток от деления на 2 равен 0?
      p = p * x[i];
  }
  return p;
}
int main() {
  int a[5]; // объявлен массив a  из 5 элементов
  int i;
  int pr;
  // Ввод элементов массива
  for(i=0; i<5; i++) {
    printf("a[%d] = ", i);
    scanf("%d", &a[i]); // &a[i] - адрес i-го элемента массива
  }
  pr = func(a, 5); // вычисление произведения
  printf("\n pr = %d", pr); // вывод произведения четных элементов
  getchar();
  getchar();
  return 0;
}

Результат выполнения
Произведение четных элементов массива

Назад


Назад: Язык Си

Комментариев к записи: 9

  • Дмитрий

    «Пример Дан массив размерности n. Вычислить произведение четных элементов»

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

     


    • Елена Вставская

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


  • Здравствуйте, а что хранится в массиве в случае объявления массива без инициализации?


    • Елена Вставская

      В случае объявления массива без инициализации в массиве хранится мусор. До инициализации значения элементов массива использовать нельзя.


      • Спасибо за ответ, правильно я понимаю, «мусор» — это то, что было в оперативной памяти на данный момент?


        • Елена Вставская

          Не могу утверждать на 100%, что это то, что хранилось в оперативной памяти на данный момент.
          Мусор — это неизвестные пользователю значения.



  • Владимир

    Здравствуйте, для чего пишется getchar 2-жды в конце каждой программы?


    • Елена Вставская

      Владимир, getchar() дважды пишется в программах, которые используют ввод с помощью scanf() или cin. Дело в том, что когда пользователь при вводе нажимает Enter, генерируются сразу два символа — перевод строки и возврат каретки. Если в конце программы написать один getchar(), то программа прекратит свое выполнение (закроет консоль), поскольку оставшийся в буфере символ возврата каретки будет воспринят функцией getchar() как введенный.
      Поэтому есть простое правило: если в программе использовался ввод с помощью scanf() или cin, в конце нужно дважды вызвать функцию getchar().
      В тех программах, где нет ввода, можно использовать один getchar(), например здесь.
      Альтернативой функции getchar() также может служить вызов system("pause"); из библиотеки stdlib.h. При этом пользователю будет выведено сообщение «Для продолжения нажмите любую клавишу…».


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

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