Главная Обратная связь

Дисциплины:

Архитектура (936)
Биология (6393)
География (744)
История (25)
Компьютеры (1497)
Кулинария (2184)
Культура (3938)
Литература (5778)
Математика (5918)
Медицина (9278)
Механика (2776)
Образование (13883)
Политика (26404)
Правоведение (321)
Психология (56518)
Религия (1833)
Социология (23400)
Спорт (2350)
Строительство (17942)
Технология (5741)
Транспорт (14634)
Физика (1043)
Философия (440)
Финансы (17336)
Химия (4931)
Экология (6055)
Экономика (9200)
Электроника (7621)


 

 

 

 



Использование символьного массива



Рассмотрим в качестве примера простую программу:

main()

{

char msg[30];

strcpy(msg,”Hello”);

puts(msg);

}

[30] после msg, предписывает компилятору выделить память для 29 символов, т.е. для массива из 29 переменных типа char (30-е знакоместо будет заполнено нулевым символом \0 -он часто называется нулевым завершителем). Переменная msg не содержит символьное значение она хранит адрес (некоторое место в памяти) первого из 29 переменных типа char.

Когда компилятор обнаруживает оператор strcpy(msg,”Hello”); он делает две вещи: создает строку “Hello” с нулевым символом(\0) на конце в некотором месте файла объектного кода, вызывает подпрограмму strcpy, которая копирует символы этой строки по одному в участок памяти, указываемой переменной msg. Когда вызывается функция puts(msg), ей передается значение msg - адрес первой буквы, на которую он указывает. Затем puts проверяет, не был ли символ по этому адресунулевым. Если да, то функция работу заканчивает, иначе puts добавляет единицу к адресу и делает проверку на нулевой символ снова.

3. Обработка строк. Ниже показаны часто используемые пары функций, описание ко­торых находиться в файле string. h.

Функция Выполняемое действие

strlen (str)Возвращает длину строки в массиве str

strcру (strl, str2)Копирует строку str2 в массив strl

strcat (strl, str2)Добавляет строку str2 к концу строки в массиве strl.

strcmp(strl, str2)Сравнивает с учетом регистра пары символов, имеющих одни и те же индексы, в двух строках и возвращает целое число:

0 - если все пары символов совпадают, т. е. строки одинаковые

> 0 - если в strlпопался символ с номером больше чем в str2

< 0 - если в strlпопался символ с номером меньше чем в str2

strncpy (strl, str 2, n)Копирует первые nсимволов строки str2 в массивstrl

strncat(strl, str2, n)Добавляет первые псимволов строки str2к концу строки в массиве strl.

strncmp (strl, str2, n)Сравнивает с учетом регистра первые псимволов в строках strlи str2

strchr (str, ch)Ищет символ ehв строке strи возвращает его адрес.

в случае отсутствия в strуказанного символа возвращает 0.

strstr (strl, str2)Ищет строку str2 в строке strlи возвращает ее адpec вслучае отсутствия в strlуказанной строки возвращает 0.

4. Преобразование строк. Описание этих функций находиться в файле stdlib. h.

Функция Выполняемое действие

atoi (str)Преобразует содержимое строки в целое число типа int. atol(str)Преобразует содержимое строки в целое число типа long int.

atoll (str)Преобразует содержимое строки в целое число типа long ling int.

atof (str)Преобразует содержимое строки в дробное число типа double.

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

 

Использование указателя на символ

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

main()

{

char *msg;

msg = “Hello”;

puts(msg);

}

Звездочка (*) впереди msg указывает компилятору, что msg является указателем на символ; другими словами, msg может хранить адрес некоторого символа. Однако при этом компилятор не выделяет никакого пространства для размещения символов и не инициализирует msg каким-либо конкретным значением.

Когда компилятор находит оператор msg = “Hello”; он делает две вещи:

как и раньше, он создает строку “Hello”, сопровождаемую нулевым символом, где-то внутри файла объектного кода,

присваивает начальный адрес этой строки переменной msg.

Команда puts работает также, как и раньше.

Указатели

Большинство типов переменных, которые рассмотрены ранее, в основном содержали данные, т.е. текущую информацию для работы программы. Но иногда важно знать место расположения данных, а не их значение. Именно для этого используются указатели. Указатель- это переменная, содержащая адрес некоторых данных в памяти ПЭВМ. Указатели используются в различных целях:

· во-первых, можно использовать указатель места расположения различных данных и структур данных. Изменением адреса в указателе можно манипулировать(создавать, считывать, изменять) информацию в различных ячейках,

во-вторых, использование указателей позволяет создавать новые переменные в процессе выполнения программы. Си позволяет программе запрашивать некоторое количество памяти (в байтах), возвращая адреса, которые можно запомнить в указателе. Этот прием известен как ДИНАМИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ; используя его программа может приспосабливаться к любому объему памяти, в зависимости от того много или мало памяти доступно ПЭВМ,

· в-третьих, использовать указатели можно для доступа к различным элементам структур данных, таким как массивы, строки или структуры.

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

Массивы

Большинство языков высокого уровня - включая и Си - позволяет определять МАССИВЫ, т.е. индексированный набор данных определенного типа. Формат задания массива в разделе объявлений следующий:

тип имя[размер]

где “тип” - тип данных элементов массива (любой из допустимых в языке, “имя” - имя массива, “размер” - размерность массива, т.е. количество элементов в массиве. Первый элемент массива это имя[0], последний - имя[размер-1]. Общий объем памяти в байтах (size), отведенных для хранения массива можно определить оператором: size = sizeof(имя) где функция sizeof как раз определяет размер памяти массива.

Можно использовать многомерные массивы, которые задаются форматом:

тип имя[размер1][размер2]...[размерN]

Двухмерные и n-мерные массивы.

Массивы, которые рассматривались выше, называют одномерными массивами, т. к. каждый элемент такого массива определяется одним индексом, указываемым внутри пары квадратных скобок. Кроме одномерных массивов в языке Си можно использовать двух­мерные и n-мерные массивы. Такие массивы декларируются с указанием соответствующе­го кoличество пар квадратных скобок и указанием в каждой паре размера.

int m2[5][10] ; // декларация двухмерного массива

int m3[8][5][10] ; // декларация трехмерного массива int m4[3][8][5][10] ;// декларация четырехмерного массива

Двухмерный массив m2можно рассматривать как таблицу или матрицу, содержащую 5 строк и 10 столбцов. Трехмерный массив можно рассматривать как набор из 8 таблиц или матриц, содержащих 5 строк и 10 столбцов. Четырехмерный массив m4 можно рас­сматривать как три набора из 8 таблиц или матриц, содержащих 5 строк и 10 столбцов.

Нумерация элементов в n-мерных массивах делается так же, как и в одномерных мас­сивах, целыми числами начиная с нуля.

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

m2[3] [6] = 0 ;

присваивает элементу массива m2, лежащему на пересечении 3-й строки и 6-го столбца значение 0.

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

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

for(j =0; j < 10; j++)

m2[i][j] = 0 ;

Поскольку при работе с n-мерными массивами используются вложенные циклы, в ка­ждом цикле должна использоваться своя переменная целого типа.

В памяти двухмерные массивы располагаются по строкам. В начале массива всегда будут расположены переменные 0-й строки, затем 1-й и т. д. Трехмерные массивы распо­лагаются по таблицам. В начале массива всегда будет располагаться таблица с номером 0, затем с номером 1 и т. д. Сами таблицы будут расположены по строкам.

Поскольку n-мерный массив в памяти располагается так же, как и одномерный, все за­дачи с n-мерными массивами могут быть реализованы и с помощью одномерных масси­вов. Только программист должен взять на себя расчет положения нужной переменной, ко­торый выполняют операции [] . Ниже показана формула для расчета положения пере­менной в двухмерном массиве, содержащем 10 столбцов:

адреспеременной = адресмассива + (номерстроки * 10 + номерстолбца) * раз-мерпеременной.

для трехмерного массива, содержащего таблицы 5x10 формула будет выглядеть сле­дующим образом:

адреспеременной = адресмассива + (номертаблицы * 50 + номерстроки * 10 + но-мерстолбца) * размерпеременной.

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

По стандарту 1999 г. компиляторы в языке Си должны поддерживать массивы пере­менных размеров, в которых размеры можно задавать не константой, а переменной целого типа или вычисляться. Однако не все компиляторы могут поддерживать такие массивы. Кроме того, в языке C++, а это дальнейшее продолжение языка Си, такие массивы не под­держиваются.

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

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

m2[0][i] = 0 ;_

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

mЗ [5] [3] [б] - переменная таблицы с номером 5, находящаяся на пересечении стро­ки с номером 3 и столбца с номером 6 массива mЗ;

mЗ [5] [3] - адрес строки с номером 3 в таблице с номером 5 массивах mЗ;

mЗ [5] - адрес таблицы с номером 5 массива mЗ;

mЗ - адрес самого массива mЗ.

Благодаря этим возможностям двухмерный массив типа char можно рассматривать как массив строк, а адрес нужной строки будет получен путем указания ее номера в одной паре квадратных скобок. Ниже показан пример вывода строк из массива ms на экран:______

char ms[10][100] ; // Массив для хранения 10 строк каждая

// размером не более 99 символов

for(i = 0/ i < 10; i++) puts( ms[i] ) ;

Инициализация массивов

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

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

int m[5] = {5,8,7,9,2} ;

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

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

Распределение значений по переменным массива будет сделано согласно порядку раз­мещения этих переменных в памяти.

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

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

При инициализации двухмерных и n-мерных массивов лучше воспользоваться про­бельными символами и расположить числа в списке инициализации в виде таблицы или набора таблиц, как показано ниже:

int m2[3][4] = { 3,6,5,8,

7,9,1,3, 2,7,6,8} ;

int m3[2][2][3] = { 3,6,5, // 0-я таблица

8,7,9, 1,3,2, // 1-я таблица

7,6,8 } ;

При таком расположении лучше видно, какие значения, в какие переменные массива попадают.

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

int m[]= {5,8,7,9,2} ;

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

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

При инициализации двухмерных и n-мерных массивов, значения для отдельных эле­ментов этих массивов (строк, таблиц, ...) можно заключать в пары фигурных скобок. Этот вариант удобен в том случае, когда для некоторых элементов необходимо указать непол­ные списки инициализации:

int m2[3][4] = {{3,6,5,8},

{7,9}, {2,7,6,8}};

int m3[2][2][3] = {{{3,6,5}, // 0-я таблица

{8,7,9}},

{1,3,2}, // 1-я таблица

{7,6,8}}} ;

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

как обычные массивы:

char s[10] = {72,101,108,108,111} ; // Hello

char s2[10] = {'H','e,,,l','l','o'};_

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

char sЗ[10] = "Hello" ;_

Массивы строк инициализируют списком строк:

char ms[5][10] = {"if", "for", "while", "switch", "break"} ;

 

Структуры

Массивы и указатели позволяют создавать список элементов одного типа. А что, если необходимо создать нечто, содержащее элементы различного типа? Для этого используются СТРУКТУРЫ.

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

typedef struct{

char name[25];

char class;

short subclass;

float decl,RA,dist;

} star;

· Здесь определена структура (struct) типа star. Сделав такое

"Age "%d\n"

описание в начале программы, можно дальше использовать этот определенный тип данных:

 

main()

{

star mystar;

strcpy(mystar.name,”Епсилон Лебедя”);

mystar.class = ‘N’;

mystar.subclass = 2;

mystar.decl = 3.5167;

mystar.RA = -9.633;

mystar.dist = 0.303;

}/* конец функции main() */

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

Операции и функции ввода.

Операции

Итак, теперь можно вводить данные в программу. Но в программе надо что-то с ними делать - как-то манипулировать с ними, используя допустимые в Си операции.

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

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

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

Каждая операция имеет определенный приоритет. Приоритет определяет порядок вы­полнения операций в выражении.

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

Операция присваивания

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

Кроме простого присваивания в Си существуют сложные операции присваивания, ко­торые позволяют сократить запись выражений типа а= а+ b, где одна и та же переменная стоит справа и слева от операции присваивания и представить их в виде а+=b.

Все сложные операции присваивания показаны ниже:

Для арифметических операций

+= сложение с присваиванием

- = вычитание с присваиванием

*= умножение с присваиванием

/= деление с присваиванием

%= присваивание остатка от деления

Для побитовых операций

«= сдвиг влево с присваиванием

»= сдвиг вправо с присваиванием

&= побитовое И с присваиванием

| = побитовое ИЛИ с присваиванием

^= ИСКЛЮЧАЮЩЕЕ ИЛИ с присваиванием.

 



Просмотров 1214

Эта страница нарушает авторские права




allrefrs.su - 2025 год. Все права принадлежат их авторам!