Двумерные массивы в c. Массив указателей. Типичные ошибки. Tag Archives: матрицы Написать матрицу в программе си

Формулировка задачи:

Всем добрый день) Мне хотелось бы по возможности получить Вашу помощь с данным заданием, провел за ним достаточно времени, хочу разобраться, где у меня ошибки. Собственно само задание: "Напишите программу, которая создает матрицу 5*5 и заполняет ее полностью +. Пользователю должно быть предложено меню: Матрица выглядит так: + + + + + + + + + + + + + + + + + + + + + + + + + Опции: (1) Заполнить все поля знаком 0 (2) Заполнить обе диагонали 0 (3) Заполнить заданное поле 0 (столбец, строка) (4) Обновить: Заполнить все поля снова + (5) Конец программы " Пример выведения для 2 опции: Матрица выглядит сейчас так: 0 + + + 0 + 0 + 0 + + + 0 + + + 0 + 0 + 0 + + + 0 Какие у меня проблемы: 1. Почему-то матрица в случае вывода через arr [i][j] заполняется не +, а левыми символами 2. В случае с выбором 2 опции, вроде бы диагонали заданы правильно, но появляются "лишние" нули и выводится не один раз (почему не один раз я знаю, но не совсем понимаю, как это корректно исправить) 3. Как правильно задать именно нужный адрес с клавиатуры и "прикрутить" его к матрице, чтобы именно это поле менялось на ноль. 4. Как сделать лучше реализацию цикла do while, чтобы программа продолжала выполняться, пока не будет нажата кнопка 5. 5. Как реализовать вывод "красивше"? Вот мой код: #include int main() { char arr; int i, j; int choice; int col, row; for (i = 0; i<5; i++) // цикл по строкам { for (j = 0; j<5; j++) // цикл по столбцам { arr[i][j]= 43; } } printf("Матрица выглядит так:"); printf(", arr [i][j]); printf("\Опции: \n (1) Заполнить все поля знаком 0 \n (2) Заполнить обе диагонали 0 \n (3) Заполнить заданное поле 0 (столбец, строка)\n (4) Обновить: Заполнить все поля снова + \n (5)Конец программы \n" ); scanf("%i",&choice); do { switch (choice){ case 1: { for (i = 1; i<6; i++) // цикл по строкам { for (j = 1; j<6; j++) // цикл по столбцам { arr[i][j]= "O"; } } } printf("Опция: %i \n Матрица выглядит теперь так:" , choice); printf("\n%c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n" , arr [i][j]); }break; case 2:{ if (i==j || i==4-j) arr[i][j]= "O"; printf("Опция: %i \n Матрица выглядит теперь так" , choice); printf("\n%c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n" , arr [i][j]); printf("\n" ); } break; case 3: { for (i = 0; i<6; i++) // цикл по строкам { for (j = 0; j<6; j++) // цикл по столбцам { { printf(" Введите столбец и стрку = "); scanf("%i", &arr); arr= "0"; } // Вывод элементов массива for (i = 0; i<5; i++) { // цикл по строкам for (j = 0; j<5; j++) { // цикл по столбцам printf("Опция: %i \n Матрица выглядит теперь так: " , choice); printf("\n%c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n" , arr [i][j]); printf("\n" ); } } // перевод на новую строку } } } break; case 4:{ for (i = 0; i<6; i++) // цикл по строкам { for (j = 0; j<6; j++) // цикл по столбцам { arr[i][j]= "+"; } } printf("Опция: %i \n Матрица выглядит теперь так " , choice); printf("\n%c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n%c %c %c %c %c\n %c %c %c %c %c\n" , arr [i][j]); } break; } while (choice!=5); break; return 0; }

Код к задаче: «Заполнение матрицы символами»

Textual #include #include int main() { char arr; int i, j; int choice; int col, row; printf("Матрица выглядит так:\n\n"); for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { printf("+ ", arr[i][j]); } printf("\n"); } printf("\nОпции: \n (1) Заполнить все поля знаком 0 \n (2) Заполнить обе диагонали 0 \n " "(3) Заполнить заданное поле 0 (столбец, строка)\n (4) Обновить: Заполнить все поля снова знаком" " + \n (5) Конец программы \n\n"); do{ printf("Сделайте выбор: \n"); scanf("%i", &choice); }while(choice < 1 || choice > 5); switch (choice) { case 1: { printf("Опция: %i \n", choice); printf("Матрица выглядит теперь так:\n\n"); for (i = 0; i < 5; i++) // цикл по строкам { for (j = 0; j < 5; j++) // цикл по столбцам { printf("0 ", arr[i][j]); } printf("\n"); } } break; case 2: { printf("Опция: %i \n", choice); printf("Матрица выглядит теперь так:\n\n"); for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { if(i == j || i == 4 - j) { arr[i][j] = 0; printf("%i ", arr[i][j]); } else { printf("+ "); } } printf("\n"); } } break; case 3: { printf("Введите столбец и стрку: \n"); scanf(" %i %i", &col, &row); printf("Опция: %i \n", choice); printf("Матрица выглядит теперь так:\n\n"); // Вывод элементов массива for (i = 0; i < 5; i++) { // цикл по строкам for (j = 0; j < 5; j++) { // цикл по столбцам if(i == col - 1 || j == row - 1) { arr[i][j] = 0; printf("%i ", arr[i][j]); } else { printf("+ ");} } printf("\n"); // перевод на новую строку } } break; case 4: { printf("Опция: %i \n", choice); printf("Матрица выглядит так:\n\n"); for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { printf("+ ", arr[i][j]); } printf("\n"); } } break; case 5: { exit(0); } } return 0; }

Аннотация: Приводятся правильные и неправильные способы реализации матриц и многомерных массивов на языке Си. Работа с матрицами иллюстрируется на примере приведения матрицы к ступенчатому виду методом Гаусса. Рассматриваются методы работы с файлами, использующие функции ввода-вывода из стандартной библиотеки ANSI. Приводятся способы работы с символами и текстовыми строками с помощью функций стандартной библиотеки. Материал иллюстрируется примерами, включающими программу "wc" подсчета символов, слов и строк в файле и программу "Записная книжка", которая позволяет находить телефон человека по его имени, а также сохранять и модифицировать содержимое книжки.

Представление матриц и многомерных массивов

Специального типа данных матрица или многомерный массив в Си нет, однако, можно использовать массив элементов типа массив . Например, переменная a представляет матрицу размера 3x3 с вещественными элементами:

Элементы матрицы располагаются в памяти последовательно по строкам: сначала идут элементы строки с индексом 0, затем строки с индексом 1, в конце строки с индексом 2 (в программировании отсчет индексов всегда начинается с нуля, а не с единицы!). При этом выражение

где i -- целая переменная , представляет собой указатель на начальный элемент i -й строки и имеет тип double* .

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

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

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

Пусть нужна матрица , размер которой определяется во время работы программы. Тогда пространство под нее надо захватывать в динамической памяти с помощью функции malloc языка Си или оператора new языка C++. При этом в динамической памяти захватывается линейный массив и возвращается указатель на него. Рассмотрим вещественную матрицу размером m строк на n столбцов. Захват памяти выполняется с помощью функции malloc языка Си

double *a; . . . a = (double *) malloc(m * n * sizeof(double));

или с помощью оператора new языка C++:

double *a; int m, n; . . . a = new double;

При этом считается, что элементы матрицы будут располагаться в массиве следующим образом: сначала идут элементы строки с индексом 0 , затем элементы строки с индексом 1 и т.д., последними идут элементы строки с индексом m - 1 . Каждая строка состоит из n элементов, следовательно, индекс элемента строки i и столбца j в линейном массиве равен

(действительно, поскольку индексы начинаются с нуля, то i равно количеству строк, которые нужно пропустить, i * n - суммарное количество элементов в пропускаемых строках; число j равно смещению внутри последней строки). Таким образом, элементу матрицы в строке i и столбце j соответствует выражение

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

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

double **a; // Адрес массива указателей int m, n; // Размеры матрицы: m строк, n столбцов int i; . . . // Захватывается память под массив указателей a = (double **) malloc(m * sizeof(double *)); for (i = 0; i < m; ++i) { // Захватывается память под строку с индексом i a[i] = (double *) malloc(n * sizeof(double)); }

После этого к элементу a ij можно обращаться с помощью выражения

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

Многомерные массивы реализуются аналогично матрицам. Например, вещественный трехмерный массив размера 4 x 4 x 2 описывается как

обращение к его элементу с индексами x , y , z осуществляется с помощью выражения

Многомерные массивы переменного размера с числом индексов большим двух встречаются в программах довольно редко, но никаких проблем с их реализацией нет: они реализуются аналогично матрицам. Например, пусть надо реализовать трехмерный вещественный массив размера m x n x k . Захватывается линейный массив вещественных чисел размером m * n * k :

double *a; . . . a = (double *) malloc(m * n * k * sizeof(double));

Доступ к элементу с индексами x , y , z осуществляется с помощью выражения

a[(x * n + y) * k + z]

Пример: приведение матрицы к ступенчатому виду методом Гаусса

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

Напомним, что матрица A с элементами a ij называется ступенчатой, если она обладает следующими двумя свойствами:

  1. если в матрице есть нулевая строка, то все строки ниже нее также нулевые;
  2. пусть a ij не равное 0 -- первый ненулевой элемент в строке с индексом i , т.е. элементы a il = 0 при l < j . Тогда все элементы в j -м столбце ниже элемента a ij равны нулю, и все элементы левее и ниже a ij также равны нулю: a kl = 0 при k > i и l =< j .

Ступенчатая матрица выглядит примерно так:

здесь тёмными квадратиками отмечены первые ненулевые элементы строк матрицы. Белым цветом изображаются нулевые элементы, серым цветом - произвольные элементы.

Алгоритм Гаусса использует элементарные преобразования матрицы двух типов.

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

Элементарные преобразования сохраняют определитель и ранг матрицы, а также множество решений линейной системы. Алгоритм Гаусса приводит произвольную матрицу элементарными преобразованиями к ступенчатому виду. Для ступенчатой квадратной матрицы определитель равен произведению диагональных элементов, а ранг - числу ненулевых строк (рангом по определению называется размерность линейной оболочки строк матрицы).

Метод Гаусса в математическом варианте состоит в следующем:

  1. ищем сначала ненулевой элемент в первом столбце. Если все элементы первого столбца нулевые, то переходим ко второму столбцу, и так далее. Если нашли ненулевой элемент в k -й строке, то при помощи элементарного преобразования первого рода меняем местами первую и k -ю строки, добиваясь того, чтобы первый элемент первой строки был отличен от нуля;
  2. используя элементарные преобразования второго рода, обнуляем все элементы первого столбца, начиная со второго элемента. Для этого от строки с номером k вычитаем первую строку, умноженную на коэффициент a k1 /a 11 .
  3. переходим ко второму столбцу (или j -му, если все элементы первого столбца были нулевыми), и в дальнейшем рассматриваем только часть матрицы, начиная со второй строки и ниже. Снова повторяем пункты 1) и 2) до тех пор, пока не приведем матрицу к ступенчатому виду.

Программистский вариант метода Гаусса имеет три отличия от математического:

r = -a kj /a ij . a k = a k + r * a i

Такая схема работает нормально только тогда, когда коэффициент r по абсолютной величине не превосходит единицы. В противном случае, ошибки округления умножаются на большой коэффициент и, таким образом, экспоненциально растут. Математики называют это явление неустойчивостью вычислительной схемы. Если вычислительная схема неустойчива, то полученные с ее помощью результаты не имеют никакого отношения к исходной задаче. В нашем случае схема устойчива, когда коэффициент r = -a kj /a ij не превосходит по модулю единицы. Для этого должно выполняться неравенство

|a ij | >= |a kj | при k > i

Отсюда следует, что при поиске разрешающего элемента в j -м столбце необходимо найти не первый попавшийся ненулевой элемент, а максимальный по абсолютной величине . Если он по модулю не превосходит , то считаем, что все элементы столбца нулевые; иначе меняем местами строки, ставя его на вершину столбца, и затем обнуляем столбец элементарными преобразованиями второго рода.

Ниже дан полный текст программы на Си , приводящей вещественную матрицу к ступенчатому виду. Функция , реализующая метод Гаусса , одновременно подсчитывает и ранг матрицы. Программа вводит размеры матрицы и ее элементы с клавиатуры и вызывает функцию приведения к ступенчатому виду. Затем программа печатает ступенчатый вид матрицы и ее ранг . В случае квадратной матрицы также вычисляется и печатается определитель матрицы , равный произведению диагональных элементов ступенчатой матрицы.

При реализации метода Гаусса используется схема построения цикла с помощью инварианта, см. раздел 1.5.2. В цикле меняются две переменные -- индекс строки i , 0 =< i < m - 1 , и индекс столбца j , 0 =< j < n - 1 . Инвариантом цикла является утверждение о том, что часть матрицы (математики говорят минор ) в столбцах 0,1,...j - 1 приведена к ступенчатому виду и что первый ненулевой элемент в строке i - 1 стоит в столбце с индексом меньшим j . В теле цикла рассматривается только минор матрицы в строках i,...,m - 1 и столбцах j,...,n - 1 . Сначала ищется максимальный по модулю элемент в j -м столбце. Если он по абсолютной величине не превосходит то j увеличивается на единицу (считается, что столбец нулевой). Иначе перестановкой строк разрешающий элемент ставится на вершину j -го столбца минора, и затем столбец обнуляется элементарными преобразованиями второго рода. После этого оба индекса i и j увеличиваются на единицу. Алгоритм завершается, когда либо i = m , либо j = n . По окончании алгоритма значение переменной i равно числу ненулевых строк ступенчатой матрицы, т.е. рангу исходной матрицы.

Для вычисления абсолютной величины вещественного числа x типа double мы пользуемся стандарной математической функцией fabs (x) , описанной в стандартном заголовочном файле " math .h.

#include // Описания функций ввода-вывода #include // Описания математических функций #include // Описания функций malloc и free // Прототип функции приведения матрицы // к ступенчатому виду. // Функция возвращает ранг матрицы int gaussMethod(int m, // Число строк матрицы int n, // Число столбцов матрицы double *a, // Адрес массива элементов матрицы double eps // Точность вычислений); int main() { int m, n, i, j, rank; double *a; double eps, det; printf("Введите размеры матрицы m, n: "); scanf("%d%d", &m, &n); // Захватываем память под элементы матрицы a = (double *) malloc(m * n * sizeof(double)); printf("Введите элементы матрицы:\n"); for (i = 0; i < m; ++i) { for (j = 0; j < n; ++j) { // Вводим элемент с индексами i, j scanf("%lf", &(a)); } } printf("Введите точность вычислений eps: "); scanf("%lf", &eps); // Вызываем метод Гаусса rank = gaussMethod(m, n, a, eps); // Печатаем ступенчатую матрицу printf("Ступенчатый вид матрицы:\n"); for (i = 0; i < m; ++i) { // Печатаем i-ю строку матрицы for (j = 0; j < n; ++j) { printf(// Формат %10.3lf означает 10 "%10.3lf ", // позиций на печать числа, a // 3 знака после точки); } printf("\n"); // Перевести строку } // Печатаем ранг матрицы printf("Ранг матрицы = %d\n", rank); if (m == n) { // Для квадратной матрицы вычисляем и печатаем // ее определитель det = 1.0; for (i = 0; i < m; ++i) { det *= a; } printf("Определитель матрицы = %.3lf\n", det); } free(a); // Освобождаем память return 0; // Успешное завершение программы } // Приведение вещественной матрицы // к ступенчатому виду методом Гаусса с выбором // максимального разрешающего элемента в столбце. // Функция возвращает ранг матрицы int gaussMethod(int m, // Число строк матрицы int n, // Число столбцов матрицы double *a, // Адрес массива элементов матрицы double eps // Точность вычислений) { int i, j, k, l; double r; i = 0; j = 0; while (i < m && j < n) { // Инвариант: минор матрицы в столбцах 0..j-1 // уже приведен к ступенчатому виду, и строка // с индексом i-1 содержит ненулевой эл-т // в столбце с номером, меньшим чем j // Ищем максимальный элемент в j-м столбце, // начиная с i-й строки r = 0.0; for (k = i; k < m; ++k) { if (fabs(a) > r) { l = k; // Запомним номер строки r = fabs(a); // и макс. эл-т } } if (r <= eps) { // Все элементы j-го столбца по абсолютной // величине не превосходят eps. // Обнулим столбец, начиная с i-й строки for (k = i; k < m; ++k) { a = 0.0; } ++j; // Увеличим индекс столбца continue; // Переходим к следующей итерации } if (l != i) { // Меняем местами i-ю и l-ю строки for (k = j; k < n; ++k) { r = a; a = a; a = (-r); // Меняем знак строки } } // Утверждение: fabs(a) > eps // Обнуляем j-й столбец, начиная со строки i+1, // применяя элем. преобразования второго рода for (k = i+1; k < m; ++k) { r = (-a / a); // К k-й строке прибавляем i-ю, умноженную на r a = 0.0; for (l = j+1; l < n; ++l) { a += r * a; } } ++i; ++j; // Переходим к следующему минору } return i; // Возвращаем число ненулевых строк }

Вообще-то программировать расчёт определителей не нужно. Их умеет считать, скажем, встроенная функция МОПРЕД из Excel:

  • набираем элементы матрицы в смежных ячейках, например, матрица размерностью 4*4 показана на картинке;
  • в нужной ячейке вводим формулу (в нашем случае =МОПРЕД(A1:D4) и нажимаем Enter:)

Не труднее вычислить и в MathCAD - просто нажать кнопку на панели матриц...

Но иногда нужен алгоритм, а не ответ... вот немного кода на консольном C++, на совершенство он не претендует, но нули в матрице или "не тот" порядок элементов смущать функцию determinant не должны. Пример из main - 1001-й на работу с динамической матрицей средствами C++ :) Остальное закомментировано в исходнике.

#define bool int #define true 1 #define false 0 int search (double **a, int m, int n, double what, bool match, unsigned int &uI, unsigned int &uJ, unsigned int starti, unsigned int startj) { // Поиск в матрице a[m][n] элемента с указанным значением what // Возвращаеются его номер строки и столбца uI, uJ, если элемент найден. // match - искать равный элемент или отличный от указанного. // Вернёт 0 - не найдено, не 0 - найдено if ((!m) || (!n)) return 0; if ((starti >= n) || (startj >= m)) return 0; for (unsigned int i = starti; i < n; i++) for (unsigned int j = startj; j < m; j++) { if (match == true) { if (a[i][i] == what) { uI = i; uJ = j; return 1; } } else if (a[i][j] != what) { uI = i; uJ = j; return 1; } } return 0; } void swaprows (double **a, int n, int m, unsigned int x1, unsigned int x2) { //Меняет в матрице a[n][m] строки с номерами x1 и x2 местами if ((!n) || (!m)) return; if ((x1 >= n) || (x2 >= n) || (x1 == x2)) return; double tmp; for (unsigned int x = 0; x < m; x++) { tmp = a[x]; a[x] = a[x]; a[x] = tmp; } return; }; void swapcolumns (double **a, int n, int m, unsigned int x1, unsigned int x2) { //Меняет в матрице a[n][m] столбцы с номерами x1 и x2 местами if ((!n) || (!m)) return; if ((x1 >= m) || (x2 >= m) || (x1 == x2)) return; double tmp; for (unsigned int x = 0; x < n; x++) { tmp = a[x]; a[x] = a[x]; a[x] = tmp; } return; }; double determinant (double **a, unsigned int n) { //Вычисление определителя квадратной матрицы a[n][n] unsigned int m = n; if (m == 0) return 0; if (m == 1) return a; if (m == 2) return (a * a - a * a); bool sign = false; // смена знака определителя. по умолчанию - нет double det = 1; // определитель double tmp; unsigned int x, y; for (unsigned int i = 0; i < n; i++) { // цикл по всей главной диагонали if (a[i][i] == 0) { // если элемент на диагонали равен 0, то ищем ненулевой элемент в матрице if (!search(a,m,n,0, false, y, x, i, i)) return 0; // если все элементы нулевые, то опр. = 0 if (i != y) { // меняем i-ую строку с y-ой swaprows(a,m,n,i, y); sign = !sign; } if (i != x) { // меняем i-ый столбец с x-ым swapcolumns(a,m,n,i, x); sign = !sign; } // таким образом, в a[i][i], теперь ненулевой элемент. } // выносим элемент a[i][i] за определитель det *= a[i][i]; tmp = a[i][i]; for (x = i; x < m; x++) { a[i][x] = a[i][x] / tmp; } // таким образом a[i][i] теперь равен 1 // зануляем все элементы стоящие под (i, i)-ым, // при помощи вычитания с опр. коеффициентом for (y = i + 1; y < n; y++) { tmp = a[y][i]; for (x = i; x < m; x++) a[y][x] -= (a[i][x]*tmp); } } if (sign) return det*(-1); return det; }; #include int main () { const int n=4; int data = { 5,4,3,2, 11,-1,2,7, 0,1,0,4, -13,79,1,2 }; int i,j,k=0; double **a = new double * [n]; for (i=0; i

До этого момента, мы рассматривали только одномерные массивы, то есть, к элементу массива мы обращались через один индекс. Однако, массивы могут быть и двумерными и трехмерными и, даже, n-мерными. Многомерные массивы — это массивы, у которых есть более одного индекса. Вместо одной строки элементов, многомерные массивы можно рассматривать как совокупность элементов, которые распределены по двум или более измерениям. Вот так, например, можно визуализировать двумерный массив:

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

Int checkers; // двумерный массив

То есть, двумерный массив хорошо подходит для хранения информации на шашечном поле. Также двумерный массив можно легко использовать для хранения информации о любой другой игре — шахматы, крестики нолики, сапер и т. д. Чтобы получить доступ к любому элементу такого массива, нужно воспользоваться двумя значениями — индексами, первый индекс — это номер строки, а второй — номер столбца. Все выше сказанное относится и к n-мерным массивам. Хотя, уже 4-х мерные массивы сложновато визуализировать. Присваивать значения элементам массива очень просто, вот пример:

// присваиваем первому элементу массива значение - 5 myArray = 5;

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

// присваиваем первому элементу массива значение - 5 myArray = 10;

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

[__][__][__][__][__] [__][__][__][__] [__][__][__][__][__]

Как видите, все просто, главное помните, что нумерация строк и столбцов всегда начинается с 0. То есть, я еще раз хочу вам напомнить, что вы никогда не должны пытаться записать данные после последнего элемента массива, например, когда у вас есть массив размером — 10 элементов и вы пытаетесь присвоить значение элементу с индексом . Память для массива была выделена только для десяти элементов, (индексы от 0 до 9), поэтому элемента с индексом 10 просто не существует. В таком случае, запись в оперативной памяти может привести к непредсказуемым последствиям — например, вы можете в конечном итоге испортить работу параллельно запущенной программы. Однако, как правило, операционная система не позволит такого рода безрассудное поведение и приведет к краху программы, если та попытается получить доступ к нераспределенной памяти.

Давайте рассмотрим практический пример использования массивов в программах:

#include int main() { int i, j; int myArray; // объявляем массив размером 8*8 элементов for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) myArray[i][j] = i * j; // каждому элементу присваиваем значение произведения текущих индексов элемента массива } printf("Вот такой массив у нас получился:\n"); for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { printf("[%d][%d]=%d ", i, j, myArray[i][j]); } printf("\n"); } getchar(); }

Сразу смотрим результат работы программы:

Вот такой массив у нас получился: =0 =0 =0 =0 =0 =0 =0 =0 =0 =1 =2 =3 =4 =5 =6 =7 =0 =2 =4 =6 =8 =10 =12 =14 =0 =3 =6 =9 =12 =15 =18 =21 =0 =4 =8 =12 =16 =20 =24 =28 =0 =5 =10 =15 =20 =25 =30 =35 =0 =6 =12 =18 =24 =30 =36 =42 =0 =7 =14 =21 =28 =35 =42 =49

В этом примере, мы сначала заполняем двумерный массив произведением его индексов, строки 8 — 11 . А потом выводим на экран его содержимое, строки 13 — 20 .

Если вы хотите объявить указатель на массив, то вы не должны использовать операцию взятия адреса — & , вот пример:

Char *ptrArray; char myString; ptrArray = myString; // указателю присваиваем адрес первого элемента массива myString без использования &

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

Int *ptrNumber; int number; ptrNumber = &number; // обязательно используем оператор - &

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

P.S.: После прочтения статьи, рекомендую вам отвлечься от программирования. Хороший способ это сделать — интересная игра. Достаньте смартфон и запустите свою любимую игру. А вот и полезная ссылка для фанатов андроида — скачать игры для андроид . Игр очень много и все интересные, а главное — бесплатные.

  • Сергей Савенков

    какой то “куцый” обзор… как будто спешили куда то