Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Объявление переменных-указателей




Функции strcpy(), strcat(), strncmp() и strlen().

Функции gets(), puts(), fgets(), fputs() и sprintf().

Передача массивов функциям С.

Инициализация двумерного массива.

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

Явная инициализация.

Инициализация по умолчанию.

12.6. Доступ к элементам массива.

12.7. Инициализация массивов и классы памяти.

12.8. Вычисление размера массива (sizeof()).

12.9. Выход индекса за пределы массива.

12.10. Ввод и вывод строк.

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

12.12. Массивы в качестве аргументов функций.

12.12.2. Передача массивов функциям C++.

12.13. Строковые функции и символьные массивы.

 

8. Массивы.

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

 

float debts [20];

 

объявляется, что debts — массив, состоящий из двадцати членов, или «элементов». Первый элемент массива называется debts[0], второй — debts[1], и т. д. вплоть до debts[19]. Заметим, что перечисление элементов массива начинается с 0, а не с 1. Поскольку мы объявили, что массив имеет тип float, каждому его элементу можно присвоить величину типа float. К примеру, можно писать так:

 

Раньше, например, мы говорили о строках, являющихся частным случаем массива типа char. (В общем массив типа char — это массив, элементами которого являются величины типа char. Строка — массив типа char, в котором нуль-символ ' \0' используется для того, чтобы отмечать конец строки.)

 

 

Числа, используемые для идентификации элементов массива, называются «подстрочными индексами» или просто «индексами». Индексами должны быть целые числа, и, как уже упоминалось, индексирование начинается с 0. Элементы массива размещаются в памяти последовательно, друг за другом, как показано на рисунке.

 

 

Существует огромное количество возможностей применения массивов. Ниже приводится сравнительно простой пример. Предположим, вы хотите написать программу, осуществляющую ввод 10 различных результатов спортивной игры, которые будут обрабатываться позже. Используя понятие массива, вы сможете избежать придумывания 10 различных имен переменных — по одной для каждого счета. Кроме того, для чтения данных вы можете воспользоваться циклом for:

 

 

/* ввод счета */

main()

{

int i, score[10];

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

scanf(" %d", &a[i]); /* ввод десяти результатов */

printf(" Введены следующие результаты: \n");

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

printf(" %5d", a[i]); /* проверка правильности ввода */

printf("\n");

}

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

Применяемый здесь способ гораздо более удобен, чем использование 10 различных операторов scanf() и 10 отдельных операторов printf() для ввода и проверки десяти результатов, определяющих число набранных очков. Цикл for обеспечивает очень простой и удобный способ использования индексов массивов.

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

Чтобы вычислить среднее, мы можем добавить к нашей программе приведенный ниже фрагмент:

 

int sum, average;

for (i = 0, sum = 0; i < = 9; i ++) /* две инициализации */

sum += a[i]; /* суммирование элементов массива */

average = sum/10; /* классический метод усреднения */

printf(" Средний результат равен %d.\n", average);

 

Для нахождения максимального результата к программе можно добавить следующий фрагмент:

 

int highest;

for (highest = a[0], i = 1, i < = 9; i++)

if(a[i] > highest)

highest = a[i];

printf(" Максимальный результат равен %d.\n", highest);

 

Здееь мы начинаем с того, что полагаем переменную highest равной величине а[0]. Затем производится сравнение значения highest с каждым элементом массива. Когда обнаруживается, что некоторая величина больше текущего значения переменной highest, ей присваивается эта новая большая величина.

Теперь объединим все части программы. На псевдокоде алгоритм ее работы можно записать следующим образом:

 

ввод результатов.

эхо-печать результатов.

вычисление и печать среднего значения.

вычисление и печать максимального значения.

 

Кроме того, мы несколько обобщим нашу программу:

 

/* результаты */

#define NUM 10

main()

{

int i, sum, average, highest, score [NUM];

printf(" Укажите 10 результатов.\n");

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

scanf(" %d", &score[i]); /* ввод десяти результатов */

printf(" Введены следующие результаты:\n");

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

printf("%5d", score [i]); /* проверка правильности ввода */

printf("\n");

for (i = 0, sum = 0; i < NUM; i++)

sum + = score [i]; /* суммирование элементов массива */

average = sum/NUM; /* классический метод усреднения */

printf("Средний результат равен %d.\n", average);

for (highest = score[0], i = 1; i < NUM; i++)

if (score[i] > highest) /* какая из величин больше */

highest = score[i];

printf(" Максимальный результат равен %d.\n", highest);

}

 

Мы заменили число 10 символической константой и воспользовались тем, что выражения i <= (NUM — 1) и i < NUM эквивалентны.

Давайте сначала посмотрим, как это программа работает, а затем сделаем несколько замечаний.

 

7.7. Понятие массив.

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

Нумерация элементов начинается с нуля, поэтому temp[0] является первым, а temp[364] последним 365-элементом массива temp.

 

7.8. Массивы в С.

Массивы имеют четыре основных характеристики:

· Отдельные объекты данных в массиве называются элементами.

· Все элементы массива должны иметь одинаковый тип данных.

· Все элементы располагаются в памяти компьютера последовательно, и индекс первого элемента равен нулю.

· Имя массива является постоянным значением, представляющим собой адрес первого элемента массива.

 

7.9. Объявление массивов.

Ниже приведены примеры объявлений массивов:

 

int iarray[12]; /* массив из 12 целых чисел */

char carray[20]; /* массив из 20 символов */

 

Для указания размера массива лучше всего использовать константы, определенные посредством #define:

 

#define iARRAY_MAX 20

#define fARRAY MAX 15

int iarray[iARRAY_MAX];

float farray[fARRAY MAX];

 

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

 

#include <stdio.h>

#define iARRAY_MAX 20

int iarray[iARRAY_MAX];

main ()

{

int i;

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

...

...

...

}

return (0);

}

 

 

7.10. Проблема ввода.

Язык Си предоставляет много средств для структурирования программ. С помощью операторов while и for реализуются циклы с предусловием. Второй оператор особенно подходит для циклов, включающих в себя инициализацию и коррекцию переменной. Использование операции «запятая» в цикле for позволяет инициализировать и корректировать более одной переменной. Для тех редких случаев, когда требуется использовать цикл с постусловием, язык Си предоставляет оператор do while. Операторы break, continue и goto обеспечивают дополнительные возможности управления ходом выполнения программы.

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

 

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

Имеется три способа инициализации массивов:

· По умолчанию во время их создания. Применимо только к глобальным и статическим (static) массивам.

· Явно во время создания при помощи констант инициализации.

· Во время выполнения программы при присваивании или копировании данных в массив.

 

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

 

7.11.1. Инициализация по умолчанию.

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

 

/*09INITAR.C

Программа на С, проверяющая инициализацию массива*/

 

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iGLOBAL_ARRAY_SIZE 10

#define iSTATIC_ARRAY_SIZE 10

int iglobal_array[iGLOBAL_ARRAY_SIZE]; /*глобальный массив*/

 

main()

{

int i;

static int static_iarray[iSTATIC_ARRAY_SIZE]; /*массив static*/

int iarray[3]={2,1,0};

char carray[3]={'a','s','d'};

char sarray1[8]="Please\n";

char sarray2[]="Thenks\n";

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

printf("iglobal_array[%2d]=%d static_iarray[%2d]=%d\n",

i,iglobal_array[i],i,static_iarray[i]);

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

printf("iarray[%2d]=%d carray[%2d]=%c\n",i,iarray[i],i,carray[i]);

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

printf("sarray1[%2d]=%c sarray2[%2d]=%c\n",i,sarray1[i],i,sarray2[i]);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

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

7.11.2. Явная инициализация.

Аналогично описаниям и инициализации переменных типов int, char, float, double и других вы можете инициализировать массивы. Стандарт ANSI С позволяет задавать и инициализирующие значения любого массива, глобального или иного, описанного в любой части программы. Следующий фрагмент кода иллюстрирует описание и инициализацию четырех массивов:

 

int iarray[3] = {-1,0,1};

static float fpercent[4] = {1.141579,0.75,55E0,-.33E1};

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

char cvowels[] = {'A','a','E,'e','I','i','0','o','U','u'};

 

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

Для большинства компиляторов безразлично — указываете ли вы размер массива, или задаете список фактических значений; важно указать либо то, либо другое. Например: в программах часто описывается набор собственных сообщений об ошибках. Это можно сделать двумя способами. Вот первый из них:

 

char szInput_Error[37] = "Please enter a value between 0 — 9:\n";

/*Пожалуйста, введите число от 0 до 9*/

char szDevice_Error[16] = "Disk not ready\n";

/*Диск не готов*/

char szMomtor_Error[32] = "Program needs a color monitor.\n";

/*Программе требуется цветной монитор*/

char szWarning[44]="This operation will erase the active file!\n";

/*Данная операция уничтожит активный файл*/

 

При таком подходе необходимо считать количество символов в строке, не забывая добавить 1, чтобы учесть невидимый null-символ окончания строки \0. Это, в лучшем случае, очень утомительный для глаз метод, который чреват многими ошибками. При втором способе, показанном ниже, используются безразмерные массивы, и язык С автоматически определяет их размер:

 

char szInput_Error[] = "Please enter a value between 0 — 9:\n";

char szDevice_Error[] = "Disk not ready\n";

char szMomtor_Error[] = "Program needs a color monitor.\n";

char szWarning[] = "This operation will erase the active file!\n";

 

 

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

 

7.12. Доступ к элементам массива.

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

7.13. Инициализация массивов и классы памяти.

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

Мы знаем, что скалярные переменные можно инициализировать в описании типа при помощи таких выражений, как, например:

 

int fix = 1;

float flax = PI*2;

 

при этом предполагается, что PI — ранее введенное макроопределение. Можем ли мы делать что-либо подобное с массивом? Ответ не однозначен: и да, и нет.

Внешние и статические массивы можно инициализировать. Автоматические и регистровые массивы инициализировать нельзя.

Прежде чем попытаться инициализировать массив, давайте посмотрим, что там находится, если мы в него ничего не записали.

 

/* проверка содержимого массива */

main ()

{

int fuzzy[2]; /* автоматический массив */

static int wuzzy[2]; /* статический массив */

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

}

 

 

Программа напечатает

 

Полученный результат иллюстрирует следующее правило:

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

 

7.14. Вычисление размера массива (sizeof()).

Как вы уже знаете, операция sizeof() возвращает физический размер в байтах того объекта, к которому она применяется. Ее можно использовать с объектами любых типов, за исключением битовых полей. Часто операция sizeof() применяется для определения физического размера переменной в тех случаях, когда размер переменных этого типа может меняться от одного компьютера к другому. Вы уже видели, что в зависимости от используемой системы целые числа могут иметь длину 2 или 4 байта. Если у операционной системы запрашивается дополнительная память для размещения семи целых чисел, то необходим способ для определения количества памяти: либо 14 байт (7x2 байта на число), либо 28 байт (7x4 байта на число). В следующей программе этот вопрос решается автоматически (и печатается значение 14 для тех систем, в которых для целого числа отводится 2 байта):

 

/*09SIZEOF.C

Программа на С, использующая операцию sizeof

для определения размера массива*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iDAYS_OF_WEEK 7

 

main()

{

int ivideo_library[iDAYS_OF_WEEK]={1,2,3,4,5,6,7};

printf("There are %d number of bytes in the array"

" ivideo_library.\n",(int) sizeof(ivideo_library));

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

7.15. Выход индекса за пределы массива.

Вам, наверное, знакомо выражение: "За все нужно платить". Это справедливо и для массивов в С. "Все" — это быстрое выполнение кода программы, а "плата" — отсутствие проверки границ массива. Напомним: поскольку язык С был разработан для замены ассемблера, в целях обеспечения компактности кода, ошибки такого рода компилятор не проверяет. Поскольку компилятор никак не определяет ошибочные ситуации, вы должны быть очень осторожны при работе с граничными значениями индекса массива. Например: компилятор транслирует следующую программу без каких-либо сообщений, однако, при записи в память за границами массива она может изменить значения других переменных или даже вызвать крах программы:

 

/*09NORUN.C

НЕ ЗАПУСКАЙТЕ эту программу на С */

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iMAX 10

#define iOUT_OF_RANGE 50

 

main()

{

int inot_enough_room[iMAX], index;

for(index=0; index < iOUT_OF_RANGE; index++)

inot_enough_room[index]=index;

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

 

7.16. Ввод и вывод строк.

Хотя в С и имеется тип данных char, в нем отсутствует тип данных для символьных строк. Вместо этого строка должна быть представлена в виде массива символов. Каждый символ строки хранится в отдельной ячейке массива, а в последней ячейке содержится null-символ \0.

В следующей программе показаны три основных способа представления и обработки символьной строки. Массив szmode1 инициализируется посимвольно при помощи операции присваивания, массив szmode2 инициализируется при помощи функции scanf(), а массив szmode3 инициализируется при описании.

 

// 09STRING.CPP

// В этой программе на C++ показано использование строк

 

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

main()

{

char szmode1[4], //car

szmode2[6]; //plane

static char szmode3[5]="ship"; //ship

szmode1[0]='c';

szmode1[1]='a';

szmode1[2]='r';

szmode1[3]='\0';

printf("\n\n\tPliase enter the mode --> plane ");

scanf("%s",szmode2);

printf("%s\n",szmode1);

printf("%s\n",szmode2);

printf("%s\n",szmode3);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

Хотя строка в массиве szmode1, "car", имеет три символа, сам массив szmode1 имеет четыре элемента — по одному на символ и еще один для null-символа. Запомните: \0 считается одним символом. Аналогичным образом, строка "plane" содержит пять символов (в строке "ship" — четыре), но требует для хранения шесть ячеек (пять для szmode3), включая null-символ. Напоминаем, что массив символов szmode3[5] можно также инициализировать, используя для этого вариант записи с фигурными скобками:

 

static char szmode3[5] = {'s','h','i','p','\0'};

 

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

 

static char szmode3[] = "ship";

 

Здесь используется безразмерный массив. Конечно, для инициализации символьного массива можно выбрать и более длинный способ, такой как для массива szmode1. Чаще для считывания строки непосредственно в массив используется функция scanf(), как это было сделано с массивом szmode2. В функции scanf() используется спецификация преобразования %s. В этом случае функция пропускает разделительные символы (символы пробела, табуляции и возврата каретки) и считывает в символьный массив szmode2 все символы до следующего разделительного. Затем автоматически добавляется null-символ. Размер массива должен быть указан достаточно большим для размещения всей строки с null-символом. Взгляните еще раз на этот оператор:

 

scanf("%s",szmode2);

 

 

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

Понятие "размерность" относится к количеству индексов, используемых для обращения к отдельному элементу массива. Все используемые до сих пор массивы были одномерными, и для доступа к элементам требовался только один индекс. Глядя на объявление массива, можно определить его размерность. Если в объявлении только одна пара квадратных скобок([]), то массив — одномерный; если две пары ([][]), то двухмерный, и так далее. Массивы, имеющие более одного измерения, называются многомерными. Для моделирования пространства максимальное число измерений обычно равно 3.

В следующем объявлении описан двухмерный массив, который инициализируется при выполнении программы:

 

/*092DARAY.C

Программа на С, иллюстрирующая использование двухмерного массива*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iROWS 4

#define iCOLUMNS 5

 

main()

{

int irow, icolumn, iadd, imultiple;

int istatus[iROWS][iCOLUMNS];

for(irow=0; irow < iROWS; irow++)

for(icolumn=0; icolumn < iCOLUMNS; icolumn++)

{

iadd=iCOLUMNS-icolumn;

imultiple=irow;

istatus[irow][icolumn]=(irow+1)*icolumn+iadd*imultiple;

}

for(irow=0; irow < iROWS; irow++)

{

printf("CURRENT ROW: %d\n",irow); /* текущая строка */

printf("RELATIVE DISTANCE FROM BASE:\n"); /*смещение относительно базы */

for(icolumn=0; icolumn < iCOLUMNS; icolumn++)

printf(" %d ",istatus[irow][icolumn]);

printf("\n\n");

}

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

 

7.17.1. Инициализация двумерного массива.

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

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

 

 

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

 

int solido[10][20][30];

 

Вы можете представить его в виде десяти двумерных массивов (каждый 20x30), поставленных друг на друга, или в виде массива из массивов. То есть это массив из 10 элементов, и каждый его элемент также является массивом. Все эти массивы в свою очередь имеют по 20 элементов, каждый из которых состоит из 30 элементов. Преимущество этого второго подхода состоит в том, что Можно довольно просто перейти к массивам большей размерности, если окажется, что вы не можете представить наглядно четырехмерный объект! Мы же останемся верны двум измерениям.

 

7.18. Массивы в качестве аргументов функций.

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

 

7.18.1. Передача массивов функциям С.

Рассмотрим функцию isum(), которая вычисляет сумму элементов массива inumeric_values[0], inumeric_values[1],..., inumeric_values[n]. Необходимы два параметра: параметр массива, названный iarray_address_received, для передачи копии адреса массива и параметр, названный imax_size, для указания индекса последнего элемента массива, который нужно добавлять. Предположив, что массив содержит целые числа, и что индекс также имеет тип int, параметры функции isum() можно описать следующим образом:

 

int isum(int iarray_address_received[], int imax_size)

 

Квадратные скобки после имени массива, включенные в объявление параметров, указывают функции isum(), что iarray_address_received — это имя массива, а не имя обычного параметра. Обратите внимание на то, что размер массива не указан в квадратных скобках. Простой параметр imax_size объявляется так же, как раньше. Для вызова функции достаточно указать:

 

isum(inumeric_values,iactual_index);

 

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

 

inumeric_values

 

на самом деле оно представляет собой краткую запись выражения

 

&inumeric_values[0]

 

На практике функцию isum() можно вызывать при помощи любого из следующих допустимых операторов:

 

isum(inumeric_values,iactual_index);

itotal = isum(&inumeric_values[0],iactual_index);

 

В любом случае внутри функции isum() имеется доступ к каждому элементу массива.

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

 

7.18.2. Передача массивов функциям C++.

Следующая программа напоминает те программы на С, которые рассматривались выше; в ней показано, как объявить и передать массив в качестве аргумента функции.

 

// 09FNCARY.CPP

// Программа на C++ иллюстрирует использование массивов в функциях

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iSIZE 5

void vadd_1(int iarray[]);

 

main()

{

int i, iarray[iSIZE]={0,1,2,3,4};

cout << "iarray before calling add_1:\n\n"; //массив перед вызовом функции

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

cout << " " << iarray[i];

vadd_1(iarray);

cout << "\n\niarray after calling add_1:\n\n"; // массив после вызова функции

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

cout << " " << iarray[i];

cout << endl;

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

void vadd_1(int iarray[])

{

int i;

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

iarray[i]++;

}

 

Результат работы программы выглядит следующим образом:

7.19. Строковые функции и символьные массивы.

Многие функции, использующие в качестве аргументов символьные массивы, до сих пор не рассматривались — это объясняется особенностями представления в С строковых данных. К этим функциям относятся следующие: gets(), puts(), fgets(), fputs(), sprintf(), stpcpy(), strcat(), strncmp(), and strlen(). Теперь, когда вы знакомы с концепцией символьных массивов и строк, оканчивающихся null-символом, объяснить принципы работы этих функций гораздо легче. Для этого проще всего рассмотреть несколько программных примеров.

 

7.19.1. Функции gets(), puts(), fgets(), fputs() и sprintf().

Следующий пример показывает использование функций gets(), puts(), fgets(), fputs() и sprintf() для форматированного ввода/вывода: Последняя пара циклов for используется для вывода элементов массива imatrix в виде прямоугольника, аналогично тому как многие люди представляют двухмерный массив.

 

/*09STRIO.C

Программа на С, использующая некоторые функции ввода/вывода строк*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iSIZE 20

 

main()

{

char sztest_array[iSIZE];

/* Введите, пожалуйста, первую строку */

fputs("Please enter the first string:", stdout);

gets(sztest_array);

/* Первая введенная строка */

fputs("The first string entered is:",stdout);

puts(sztest_array);

fputs("Please enter the second string:", stdout);

fgets(sztest_array,iSIZE,stdin);

fputs(sztest_array,stdout);

/* Это просто тест */

sprintf(sztest_array,"This was %s a test","just");

/* Функция sprintf() создана*/

fputs("sprintf() created: ",stdout);

fputs(sztest_array,stdout);

fputs("\n",stdout);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

 

Результат первого прогона программы следующий:

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

 

Please enter the first string: one two three four five

The first string entered is: one two three four five

Please enter the second string: six seven eight nine ten

The second string entered is: six seven eight ninsprintf() created

: This was just a testPlease enter the first string: The first string

entered is:e ten

The second string entered is:

 

Будьте осторожны при запуске программы. Функция gets() получает символы от стандартного устройства ввода (stdin, по умолчанию для большинства компьютеров это клавиатура) и помещает их в массив, имя которого задано в качестве параметра. Когда для завершения строки вы нажимаете клавишу <ENTER>, передается символ перевода строки. Когда функция gets() получает этот символ перевода строки, она заменяет его на null-символ, это гарантирует, что в символьном массиве оказывается не просто набор значений, а именно строка. Никаких проверок размера массива и его соответствия числу введенных символов не производится. Функция puts() отображает на экране то, что было введено при помощи функции gets(). Кроме того, в конце строки вместо null-символа она добавляет символ перевода строки. Напоминаем, что null-символ автоматически вставляет в строку функция gets(). Следовательно, строки, введенные без ошибок при помощи функции gets(), можно вывести на экран, используя puts().

Если вы пользуетесь функцией fgets(), то можете задавать максимальное число вводимых символов. Функция прекращает считывание из заданного файлового потока в тот момент, когда число считанных символов на единицу меньше, чем значение второго заданного аргумента. Поскольку размер массива sztest_array равен 20, функция fgets() считывает из stdin только 19 символов. Последнюю позицию в строке автоматически занимает null-символ; если же с клавиатуры вводился символ перевода строки, то он в строке сохранится. (В режиме отладки его можно увидеть перед null-символом.) Функция fgets() не удаляет символы перевода строки так, как это делает функция gets(); она просто добавляет null-символ в конце, и, следовательно, обеспечивает сохранение допустимой строки. Функции fgets() и fputs() являются в каком-то смысле симметричными, так же как и функции gets() и puts(). Функция fgets() не удаляет символы перевода строки, а функция fputs() не добавляет новые.

Чтобы понять важность символа перевода строки для этих функций, взгляните внимательно на результат второго прогона программы. Обратите внимание на фразу "sprintf() created..."; она следует сразу же за введенными числами "six seven eight nine". Во второй введенной строке на самом деле было на пять символов больше, чем прочитала функция fgets() (на один меньше, чем iSIZE, то есть 19). Остальные символы остались во входном буфере. Также пропущенным оказался символ перевода строки, завершающий ввод с клавиатуры. (Он остался во входном потоке, поскольку оказался по счету следующим после девятнадцатого символа.) Поэтому символ перевода строки в ней не запомнился. Поскольку функция fputs() не добавляет этих символов, следующий вывод начинается в той же строке, где закончился предыдущий. Расчет делался на прочитанный функцией fgets() и выведенный при помощи fputs() символ перевода строки, который должен был обеспечить правильность вывода на экран. Функция sprintf() используется как "строковая printf()". В ней также, как и в printf(), используется управляющая строка с символами преобразования. Особенностью sprintf() является то, что она помещает форматированный результат в строку, а не выдает его сразу же на стандартное устройство вывода. Это может быть удобно в том случае, когда один и тот же результат нужно вывести дважды, например, когда одну и ту же строку необходимо вывести и на дисплей, и на принтер.

Подведем черту:

· Функция gets() преобразует символ перевода строки в null-символ.

· Функция puts() преобразует null-символ в символ перевода строки.

· Функция fgets() оставляет символы перевода строки и добавляет null-символ.

· Функция fputs() опускает null-символ и не добавляет символы перевода строки; она использует сохраненные символы перевода строки (если они вводились).

 

7.19.2. strcpy(), strcat(), strncmp() и strlen().

Все функции, обсуждаемые в данном разделе, предопределены в заголовочном файле string.h. Всякий раз, когда вы хотите использовать какую-либо из этих функций, не забудьте включить заголовочный файл в свою программу. Помните и о том, что все строковые функции, имеющие прототипы в файле string.h, получают строковые параметры, оканчивающиеся null-символом. В следующей программе показано, как используется функция strcpy():

 

/*09STRCPY.C

Программа на С, использующая функцию strcpyO*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iSIZE 20

 

main()

{

char szsource_string[iSIZE]="Initialized String!",

szdestination_string[iSIZE];

strcpy(szdestination_string,"String Constant");

cout << "\n" << szdestination_string;

strcpy(szdestination_string,szsource_string);

cout << "\n" << szdestination_string << "\n";

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

Функция strcpy() копирует содержимое первой строки (szsource_string) во вторую строку (szdestination_string). В приведенной программе переменная szsource_string при инициализации получает значение "Initialized String!" ("Инициализированная строка"). При первом вызове функции strcpy() строка "String Constant" ("Строковая константа") непосредственно копируется в переменную szdestination_string, а при втором вызове strcpy() строка szsource_string копируется в переменную szdestination_string. Программа выдает следующие сообщения:

String Constant

Initialized String!

 

Функция strcat() объединяет вместе две отдельные строки, которые должны заканчиваться null-символом; результат также имеет в конце null-символ. В следующей программе используется уже знакомая вам функция strcpy() и представляется функция strcat():

 

/*09STRCAT.C

Программа на С, иллюстрирующая использование функции strcat()*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

#define iSTRING_SIZE 35

 

main()

{

char szgreeting[]="Good morning!", /* Доброе утро */

szname[]=" Carolyn, ", /* Кэролин, */

szmessage[iSTRING_SIZE];

strcpy(szmessage,szgreeting);

strcat(szmessage,szname);

strcat(szmessage,"how are you?"); /* как поживаете? */

printf("%s\n",szmessage);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

В этом примере две переменные, szgreeting и szname, инициализируются, а переменная szmessage — нет. При помощи функции strcpy() содержимое переменной szgreeting копируется в szmessage. Затем функция strcat() позволяет соединить содержимое переменной szname ("Carolyn,") и строку "Good morning", хранящуюся в переменной szmessage. Последний вызов функции strcat() осуществляет конкатенацию строковой константы и строки: литеральная строка "how are you?" объединяется с текущим содержимым переменной szmessage ("Good morning Carolyn,"). В результате на выходе программы получается следующее:

Good morning Carolyn, how are you?

 

В следующей программе для проверки на равенство (совпадение) двух строк используется функция strncmp():

 

/*09SRNCMP.C

Программа на С, в которой для сравнения двух строк используется

функция strncmp() с помощью функции strlen()*/

 

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

#include <stdarg.h>

#include <string.h>

using namespace std;

 

main()

{

char szstringA[]="Adam", szstringB[]="Abel";

int istringA_length, iresult=0;

istringA_length=strlen(szstringA);

if(strlen(szstringB) >= strlen(szstringA))

iresult=strncmp(szstringA, szstringB, istringA_length);

printf("The string %s found\n",iresult ==0? "was": "wasn't");

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

Функция strlen() весьма полезна: она возвращает число символов в заданной строке, не считая null-символа. Эта функция использована в приведенной программе в двух различных ситуациях; это сделало для того, чтобы пояснить способы ее применения. При первом вызове функции длина строки szstringA запоминается в переменной istringA_length. Второе обращение к функции происходит при обработке if-условия. Напоминаем, что при вычислении условий проверки получается результат ИСТИНА (не ноль или!0) и ЛОЖЬ (0). При вычислении if-условия берутся результаты двух обращений к strlen() и выполняется условная операция >=. Если длина строки szstringB >= длины строки szstringA, то вызывается функция strncmp().

13. Указатели.

13.1. Определение переменных-указателей.




Поделиться с друзьями:


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


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.512 сек.