Студопедия — МАССИВЫ. Язык Си работает с именами массивов специальным образом
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

МАССИВЫ. Язык Си работает с именами массивов специальным образом






 

 

Язык Си работает с именами массивов специальным образом.

Имя массива "a" для

 

int a[5];

 

является на самом деле указателем на его нулевой элемент.

 

То есть у нас есть переменные (ящики)

с именами

 

a[0] a[1]... a[4].

 

При этом само имя a при его использовании в программе означает &a[0]

 

a

|

|

|

V

a[0] a[1] a[2] a[3] a[4]

_________________________________________

| | | | | |

| | | | | |

| | | | | |

-----------------------------------------

 

Поэтому

 

int a[5];

 

/* Передаётся не КОПИЯ самого массива, а копия УКАЗАТЕЛЯ на его начало */

 

void f(int *a){ /* или f(int a[]), что есть равноценная запись */

printf("%d\n", a[1]);

a[2] = 7;

}

 

main (){

a[1] = 777;

f(a); /* аргумент - массив */

printf("%d\n", a[2]);

}

 

Вызов f(a); сделает именно ожидаемые вещи.

В этом примере мы видим два правила:

 

ПРАВИЛО_1:

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

в аргумент функции копируется не весь массив (жирновато будет),

а указатель на его 0-ой элемент.

 

ПРАВИЛО_2:

Указатель на начало массива

МОЖНО индексировать как сам массив.

Это вторая операция, помимо *pointer,

применимая к указателям: pointer[n].

 

Второе правило влечет за собой ряд следствий.

 

int a[5]; /* массив */

int *ptr; /* указательная переменная */

 

ptr = a; /* законно, означает ptr = &a[0]; */

 

Теперь

 

ptr[0] = 3; /* означает a[0] = 3; */

ptr[1] = 5; /* означает a[1] = 5; */

 

 

Более того. Возьмем теперь

 

ptr = &a[2];

 

 

a[0] a[1] a[2] a[3] a[4]

_________________________________________

| | | | | |

a: | | | | | |

| | | | | |

----------------------------------------------

| | | |...

ptr: | | | |

-----------------------------

-2 -1 ptr[0] ptr[1] ptr[2]

 

 

Мы как бы "приложили" к массиву a[] массив ptr[].

 

В котором

 

ptr[0] есть a[2]

ptr[1] есть a[3]

ptr[2] есть a[4]

ptr[3] находится за концом массива a[], МУСОР

 

Более того, допустимы отрицательные индексы!

 

ptr[-1] есть a[1]

ptr[-2] есть a[0]

ptr[-3] находится перед началом массива a[], МУСОР

 

Итак: индексировать можно И массивы И указатели.

 

Кстати, для имени массива a[]

*a означает то же самое, что и a[0].

 

Это обратное следствие из схожести массивов и указателей.

C

 

/* Задача: написать функцию инвертирования порядка символов

в массиве char.

A B C D ---> D C B A

В решении можно использовать рекурсию.

*/

 

/* Мы приведем рекурсивное и нерекурсивное решения (два варианта) */

#include

 

/* Сначала - несколько служебных функций. */

 

/* ФУНКЦИЯ ПОДСЧЕТА ДЛИНЫ СТРОКИ.

Как уже объяснялось, строка текста - это массив char,

в конце которого помещен символ '\0'.

Сам символ \0 не считается.

*/

int strlen(char s[]){ /* функция от массива букв */

int counter = 0; /* счетчик и одновременно индекс */

 

while(s[counter]!= '\0') /* пока не встретился признак конца текста */

counter++; /* посчитать символ */

return counter; /* сколько символов, отличных от '\0' */

}

 

/* ФУНКЦИЯ ПЕЧАТИ СТРОКИ.

Печатаем каждый элемент массива как символ при помощи putchar(c).

Как только встречаем элемент массива, равный '\0' - останавливаемся.

Заметьте, что при наличии завершающего символа нам НЕ НАДО

передавать в функцию размер массива, он нам неинтересен.

 

В конце эта функция переводит строку.

*/

int putstr(char s[]){

int i = 0; /* индекс */

 

while(s[i]!= '\0'){

putchar(s[i]);

i++;

}

putchar('\n');

return i;

}

 

/* ТЕПЕРЬ МЫ ЗАНИМАЕМСЯ ФУНКЦИЕЙ ИНВЕРТИРОВАНИЯ.

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

сдвиг элементов массива на 1 влево.

 

Исходный массив: A B C D E F

<----------

Результат: B C D E F F

-

Последний элемент удваивается.

 

n - размер массива.

Функция работает так:

 

Исходный массив: A B C D E F n=6

После i=1 B B C D E F

После i=2 B C C D E F

После i=3 B C D D E F

После i=4 B C D E E F

После i=5 B C D E F F

i=6 ==> остановка.

 

*/

void shiftLeft(char s[], int n){

int i;

 

for(i=1; i < n; i++)

s[i-1] = s[i];

}

 

/* Функция инвертирования.

Идея такова:

- если длина массива меньше или равна 1, то инвертировать нечего,

ибо массив состоит из 1 или 0 элементов.

- если длина массива > 1, то

a) Спасти нулевой элемент массива.

A B C D E F

|

|

V

tmp

 

b) Сдвинуть массив влево

B C D E F F

 

c) В последний элемент массива поместить спасенный нулевой элемент.

tmp

|

V

B C D E F A

 

 

d) Инвертировать начало массива длиной n-1.

{B C D E F}A

 

Получится:

F E D C B A

 

Что и требовалось.

 

s[] - массив,

n - его длина.

*/

void reverse(char s[], int n){

char tmp;

 

if(n <= 1) /* нечего инвертировать */

return;

 

tmp = s[0]; /* спасти */

shiftLeft(s, n); /* сдвинуть */

s[n-1] = tmp; /* переместить */

 

reverse(s, n-1); /* инвертировать начало */

}

 

/* ВТОРАЯ ВЕРСИЯ нерекурсивна. Рекурсия заменена циклом.

Длина начала массива, которую надо инвертировать,

вынесена на переменную length.

*/

void reverse1(char s[], int n){

char tmp;

int length;

 

for(length=n; length > 1; --length){

tmp = s[0];

shiftLeft(s, length);

s[length-1] = tmp;

}

}

 

char testString[] = "abcdefghijklmnopqrstuvwxyz";

 

/* Если не задать размер массива, он будет вычислен компилятором автоматически.

Он будет равен числу букв внутри "..." ПЛЮС одна ячейка для невидимого

символа '\0' на конце.

В данном случае это 27.

*/

 

void main(){

int len;

 

len = strlen(testString);

/* вычислить длину строки: 26 ('\0' на конце не считается) */

 

printf("Строка для теста: \"%s\", ее длина %d\n",

testString, len);

/* Обратите внимание на два момента:

- строку (массив char) следует печатать по формату %s

- чтобы внутри "..." напечатать символ "

надо изобразить его как \"

 

А чтобы в putchar напечатать символ ' надо писать putchar('\'');

*/

 

/* Первая инверсия */

reverse(testString, len);

putstr("Инвертированная строка:");

putstr(testString);

 

/* Вторая инверсия - возвращает в исходное состояние */

reverse1(testString, len);

putstr("Инвертированная в исходное состояние строка:");

putstr(testString);

}

C

 

/* Еще более простой вариант решения:

просто обменивать элементы местами.

 

A B C D E F G H I J

J B C D E F G H I A

| | эти

J B C D E F G H I A

J I C D E F G H B A

| | потом эти

J I C D E F G H B A

J I H D E F G C B A

| | потом эти

----> <-----

 

J I H D E F G C B A

J I H G E F D C B A

| |

J I H G E F D C B A

| |

J I H G F E D C B A

 

стоп.

*/

 

#include

 

/* Обмен значений двух переменных типа char */

void swap(char *s1, char *s2){

char c;

 

c = *s1; *s1 = *s2; *s2 = c;

}

 

void reverse(char s[], int n){

int first, last;

 

first = 0; /* индекс первого элемента массива */

last = n-1; /* индекс последнего элемента массива */

 

while(first < last){ /* пока first левее last */

swap(&s[first], &s[last]);

first++; /* сдвинуть вправо */

last--; /* сдвинуть влево */

}

}

 

char testString[] = "abcdefghijklmnopqrstuvwxyz.";

 

void main(){

int len;

 

len = strlen(testString); /* Есть такая стандартная функция */

reverse(testString, len);

printf("Инвертированная строка: %s\n", testString);

}

C

 

/* Еще один вариант решения:

сформировать ответ в дополнительном массиве,

а потом скопировать его на прежнее место.

*/

 

#include

 

char testString[] = "abcdefghijklmnopqrstuvwxyz.";

 

/* Конструкция sizeof(массив)/sizeof(массив[0])

выдает размер массива, даже если он не был явно объявлен.

Эта конструкция применяется (чаще всего) для задания массива

с размером, равным размеру уже объявленного массива.

*/

 

char tempString[ sizeof(testString) / sizeof(testString[0]) ];

 

void reverse(char s[], int n){

int i;

 

/* вывернуть, результат в tempString[] */

for(i=0; i < n; i++)

tempString[n-1-i] = s[i];

 

tempString[n] = '\0'; /* признак конца строки */

 

/* скопировать на старое место */

for(i=0; i < n; i++)

s[i] = tempString[i];

 

s[n] = '\0'; /* признак конца строки */

}

 

void main(){

int len;

 

len = strlen(testString); /* Есть такая стандартная функция */

reverse(testString, len);

printf("Инвертированная строка: %s\n", testString);

}

C

 

/* Задача инвертирования массива целых чисел */

 

#include

 

int arr[] = {1, 5, 10, 15, 20, 25, 30};

int arrLen = sizeof(arr) / sizeof(arr[0]); /* размер массива */

 

/* Распечатка массива в строку */

void printit(int row[], int n){

int i;

 

for(i=0; i < n; i++){

printf("%d", row[i]);

 

if(i == n-1) putchar('\n');

else putchar(' ');

}

}

/* Печать отступа. Отладочная функция */

void printShift(int n){

n = arrLen - n;

while(n > 0){

printf(" ");

n--;

}

}

/* Сдвиг массива */

void shiftleft(int row[], int n){

int i;

 

for(i=1; i < n; i++)

row[i-1] = row[i];

}

/* Инвертирование */

void reverse(int row[], int n){

int pocket;

 

printShift(n); /* трассировка */

printf("CALLED reverse(row, %d)\n", n); /* трассировка */

 

if(n <= 1){

printShift(n); /* трассировка */

printf("return from reverse(row, %d);\n", n); /* трассировка */

return;

}

 

pocket = row[0];

shiftleft(row, n);

row[n-1] = pocket;

 

printShift(n); /* трассировка */

printit(arr, arrLen); /* трассировка */

 

reverse(row, n-1);

 

printShift(n); /* трассировка */

printf("all done; return from reverse(row, %d);\n", n); /* трассировка */

}

void main(){

reverse(arr, arrLen);

printit(arr, arrLen);

}

 

C

 

/* Задача: написать функцию для распечатки массива целых чисел

в виде таблицы в columns столбцов.

При этом порядок элементов должен быть таков:

 

0 4 8

1 5 9

2 6 10

3 7

*/

 

/* Пусть в массиве n элементов.

Если n < columns, то мы получаем такую ситуацию (n=2, columns=4)

 

0 1 пусто пусто

 

Поэтому

 

if(n < columns) columns = n;

 

Далее, прямоугольная таблица с columns столбцами и lines строками

может содержать максимум columns*lines элементов. Поэтому:

 

columns*lines >= n

 

Вычислим число строк.

Нам нужно минимальное целое число строк, такое что

 

lines >= n/columns

 

Такое число вычисляется по формуле

 

lines = (n + (columns - 1)) / columns;

 

где деление целочисленное.

 

Далее надо только вывести формулу для индекса элемента в массиве

в зависимости от номера строки (y) и столбца (x).

 

index(x, y) = (x * lines + y);

причем если index >= n, то ничего не выводить

*/

 

#include

 

int array[100];

 

void printArray(int a[], int n, int columns){

int lines; /* число строк */

 

int x, y; /* номер колонки, номер строки - с нуля */

int index; /* индекс элемента в массиве */

 

if(n < columns) columns = n;

lines = (n + (columns-1)) / columns;

 

/* Используем вложенные циклы: по строкам, а внутри - по столбцам */

for(y=0; y < lines; y++){

for(x=0; x < columns; x++){

index = x * lines + y;

if(index >= n) /* элемент за концом массива */

break; /* прервать строку */

 

/* break выводит только

из внутреннего цикла (по столбцам) */

 

/* сделать отступ в следующую колонку */

if(x!= 0) putchar('\t');

 

printf("%02d|%d", index, a[index]);

/* Формат %02d заставляет печатать целое число

с использованием ДВУХ цифр, причем если

число состоит из одной цифры, то спереди

приписывается нуль.

*/

}

putchar('\n'); /* перейти к следующей строке */

}

}

void main(){

int i, cols;

 

/* Инициализация значений элементов массива */

for(i=0; i < 100; i++)

array[i] = i + 1;

 

for(cols=4; cols <= 13; cols++){

printf("\t\t* * * ТАБЛИЦА В %d СТОЛБЦОВ * * *\n", cols);

printArray(array, 77, cols);

putchar('\n');

}

}

C

 

#include

 

main(){

int x, y;

int COLUMNS = 11;

int LINES = 10;

 

int value;

 

/* цикл по строкам */

for(y=0; y < LINES; y++){

 

/* цикл по столбцам */

for(x=0; x < COLUMNS; x++){

 

/* что напечатать */

value = LINES * x + y;

 

/* если это не нулевой столбец, то перейти

в следующую колонку

*/

 

if(x > 0) putchar('\t');

 

/*... и в ней напечатать значение */

printf("%d", value);

 

}

putchar('\n'); /* новая строка */

}

}

C

 

/*

elem(x, y) = LINES * x + y;

 

тогда

 

elem(0, y+1) - elem(COLUMNS-1, y) = 1 + LINES - COLUMNS*LINES;

elem(x+1, y) - elem(x, y) = LINES;

*/

 

#include

 

int A = 150; /* Количество элементов */

int COLUMNS = 7; /* Количество столбцов */

int LINES; /* Количество строк */

int value; /* Значение в текущей клетке */

 

int OFFSET_NEXT_COLUMN;

int OFFSET_NEXT_LINE;

 

/* Рисуем строку таблицы */

void line(){

int col; /* номер колонки */

 

for(col=0; col < COLUMNS; col++){

if(value >= A) /* отсутствующий элемент */

printf("* ");

else printf("%03d ", value);

 

/* Увеличение при переходе в соседнюю колонку */

value += OFFSET_NEXT_COLUMN; /* 1 */

}

/* Перейти к следующей строке */

putchar('\n');

 

/* Увеличение при переходе из конца одной строки к началу следующей.

Заметим, что к value уже прибавлено OFFSET_NEXT_COLUMN из точки 1,

поэтому при переходе в начало следующей строки в сумме прибавляется

OFFSET_NEXT_COLUMN + OFFSET_NEXT_LINE равное

1 - LINES*COLUMNS + LINES,

что соответствует формуле.

*/

value += OFFSET_NEXT_LINE; /* 2 */

}

 

int main(){

int nline; /* Номер строки */

 

LINES = (A + (COLUMNS - 1)) / COLUMNS;

 

OFFSET_NEXT_COLUMN = LINES;

OFFSET_NEXT_LINE = 1 - LINES*COLUMNS;

 

for(nline=0; nline < LINES; nline++)

line();

 

/* возврат 0 из main() означает "программа завершена успешно" */

return 0;

}

C

 

/* ДВУМЕРНЫЕ МАССИВЫ */

 

/*

Двумерный массив представляет собой двумерную

прямоугольную таблицу из нумерованных переменных.

 

Он объявляется так:

 

int array[LINES][COLUMNS];

 

А индексируется так:

 

array[y][x]

 

где 0 <= y <= LINES - 1

0 <= x <= COLUMNS - 1

 

+-------------+-------------+-------------+------> ось x

| array[0][0] | array[0][1] | array[0][2] |...

+-------------+-------------+-------------+

| array[1][0] | array[1][1] | array[1][2] |...

+-------------+-------------+-------------+

| array[2][0] | array[2][1] | array[2][2] |...

+-------------+-------------+-------------+

|.........

V

ось y

 

Пока, на данной стадии знания Си,

я рекомендую вам объявлять двумерные массивы как глобальные

и не пытаться передавать их имена в функции как аргументы.

*/

 

/* Приведем пример, который заводит двумерный массив букв,

рисует в нем некую геометрическую фигуру,

и печатает этот массив.

 

Здесь мы приводим алгоритм Брезенхема для рисования прямых,

объяснения КАК он это делает мы опустим. Пардон.

*/

 

#define LINES 31 /* число строк */

#define COLUMNS 79 /* число столбцов */

 

char field[LINES][COLUMNS];

 

/* В данной программе массив НЕ является параметром,

мы работаем с ним как с глобальной переменной.

Функция рисования прямой линии, алгоритм Брезенхема.

*/

void line(int x1, int y1, int x2, int y2, char sym){

int dx, dy, i1, i2, i, kx, ky;

int d; /* "отклонение" */

int x, y;

int flag;

 

dy = y2 - y1;

dx = x2 - x1;

if (dx == 0 && dy == 0){

field[y1][x1] = sym; /* единственная точка */

return;

}

kx = 1; /* шаг по x */

ky = 1; /* шаг по y */

 

/* Выбор тактовой оси */

if(dx < 0){ dx = -dx; kx = -1; } /* Y */

else if(dx == 0) kx = 0; /* X */

 

if(dy < 0) { dy = -dy; ky = -1; }

 

if(dx < dy){ flag = 0; d = dx; dx = dy; dy = d; }

else flag = 1;

 

i1 = dy + dy; d = i1 - dx; i2 = d - dx;

x = x1; y = y1;

 

for(i=0; i < dx; i++){

field[y][x] = sym; /* нарисовать точку */

 

if(flag) x += kx; /* шаг по такт. оси */

else y += ky;

 

if(d < 0) /* горизонтальный шаг */

d += i1;

else{ /* диагональный шаг */

d += i2;

if(flag) y += ky; /* прирост высоты */

else x += kx;

}

}

field[y][x] = sym; /* последняя точка */

}

 

int main(){

int x, y;

 

/* Заполнить поле пробелами */

for(y=0; y < LINES; y++)

for(x=0; x < COLUMNS; x++)

field[y][x] = ' ';

 

/* Нарисовать картинку */

line(0,0, 0, LINES-1, '*');

line(0,0, COLUMNS-1, 0, '*');

line(COLUMNS-1, 0, COLUMNS-1, LINES-1, '*');

line(0, LINES-1, COLUMNS-1, LINES-1, '*');

 

line(0,0, COLUMNS-1, LINES-1, '\\');

line(COLUMNS-1,0, 0,LINES-1, '/');

 

/* Распечатать массив */

for(y=0; y < LINES; y++){

for(x=0; x < COLUMNS; x++)

putchar(field[y][x]);

putchar('\n');

}

return 0;

}

Last-modified: Mon, 31 Mar 1997 04:51:37 GMT

Начало формы

 







Дата добавления: 2015-03-11; просмотров: 571. Нарушение авторских прав; Мы поможем в написании вашей работы!



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

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

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

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

Деятельность сестер милосердия общин Красного Креста ярко проявилась в период Тритоны – интервалы, в которых содержится три тона. К тритонам относятся увеличенная кварта (ув.4) и уменьшенная квинта (ум.5). Их можно построить на ступенях натурального и гармонического мажора и минора.  ...

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

Опухоли яичников в детском и подростковом возрасте Опухоли яичников занимают первое место в структуре опухолей половой системы у девочек и встречаются в возрасте 10 – 16 лет и в период полового созревания...

Основные структурные физиотерапевтические подразделения Физиотерапевтическое подразделение является одним из структурных подразделений лечебно-профилактического учреждения, которое предназначено для оказания физиотерапевтической помощи...

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

Тема 2: Анатомо-топографическое строение полостей зубов верхней и нижней челюстей. Полость зуба — это сложная система разветвлений, имеющая разнообразную конфигурацию...

Studopedia.info - Студопедия - 2014-2024 год . (0.043 сек.) русская версия | украинская версия