Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник Моя первая программа на С++.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
6 Мб
Скачать
☆

Puts("Введите сведения о диске

printf("Введите название: "); gets(disc[index].name); printf("Введите описание: "); gets(disc[index].description); printf("Введите категорию: "); gets(disc[index].category); printf("Введите цену: "); scanf("%f", &dics[index].cost); printf("Введите номер ячейки: "); scanf("%d", &disc[index].number); index++;

if(index < 10)

{

printf("Желаете ввести

данные о следующем диске? Да -Y, нет -N");

scanf("%C", &flag);

}

}

while (index < 10 && (flag == 'Y' || flag == 'y')); puts("Название Номер п/п"); for (repeat = 0; repeat < index; repeat++)

disc[repeat].number);

}

printf("%s %d\n", disc[repeat].name,

Рис. 11.7. Массив структур

Определение массива, включающего 10 элементов disc, является частью определения структуры:

} disc[10];

Переменная flag ведена для того, чтобы пользователь мог указать, хочет ли он продолжить ввод инфор- мации, если заполнено меньше 10«карточек». Цикл do обеспечивает ввод элементов массива: пять пунк- тов (членов структуры) для каждого элемента массива (регистрационной карточки в картотеке коллек- ции). Переменная index используется как индекс в процессе создания картотеки.

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

В цикле do используется следующее условие:

while (index < 10 && (flag == 'Y' || flag == 'y'));

Логический оператор И указывает на то, что оба условия должны выполняться одновременно: значение переменной index должно быть меньше десяти, и переменная flag должна иметь значение 'Y' или 'y'. Если бы в условии не были поставлены внутренние скобки, компилятор Си скомбинировал бы первые два усло- вия и трактовал всю инструкцию как условие ИЛИ (рис.11.8). И если в

Рис. 11.8. Интерпретация условия при отсутствии внутренних круглых скобок

этом случае переменная flag примет значение 'y', цикл будет повторяться и после ввода значений всех элементов.

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

цикле for, в котором на дисплей выводится информация о содержании компакт-дисков и их местонахож- дении.

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

Структуры и функции

В исходном K&R-стандарте языка Си использование структур ограничено. Структуры могут передаваться в качестве аргументов только с использованием указателей, о которых мы будем говорить дальше в этой главе. Кроме того, отсутствует возможность прямого присваивания одной структуры другой, например, следующим образом:

cdrom = disc;

В современных компиляторах Си и Си++ такая возможность существует. Теперь можно непосредственно присваивать одну структурную переменную другой.

Большинство компиляторов Си++ и компиляторы Си, поддерживающие стандарт ANSI, позволяют переда- вать и возвращать структуру целиком. В Листинге11.3 продемонстрировано, как можно передать структу- ру функции. Значения членов структуры вводятся в main(), затем вся структура передается функции putdisc() для вывода. При вызове функции используется структурная переменная disc:

putdisc(disc);

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

putdisc(disk) struct CD disk;

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

Листинг 11.3. Передача структуры.

/*CD3.c*/ struct CD

main()

{

char name[20];

char description[40]; char category[12]; float cost; int number;

} disc;

{

puts("Введите сведения о диске\n\n"); printf("Введите название: "); gets(disc.name); printf("Введите описание: "); gets(disc.description); printf("Введите категорию: "); gets(disc.category); printf("Введите цену: ");

scanf("%f", &dics.cost); printf("Введите номер ячейки: "); scanf("%d", &disc.number);

putdisc(disc);

}

putdisc(disk) struct CD disk;

{

puts("Введена следующая информация о диске:\n\n"); printf("Название: %s\n", disc.name); printf("Описание: %s\n", disc.description); printf("Категория: %s\n", disc.category);

printf("Цена: %6.2f\n", disc.cost); printf("Номер п/п: %d\n", disc.number);

}

В Листинге 11.4 демонстрируется, как функция возвращает структуру. Члены структуры вводятся в функ- ции getdisc(), а затем передаются назад в main() с помощью инструкции

return(inputdisc);

Обратите внимание, что тип записи структуры (CD) используется и в определении функции, и в определе- нии переменных функции getdisc(). Это вызвано тем, что при возврате переменных, отличных от типов int или char, тип переменной следует указать в определении функции. Типом возвращаемой переменной в данном случае является структура CD, так что функция определяется следующим образом:

struct CD getdisc();

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

struct CD inputdisc;

Обратите также внимание на то, что функция getdisc() определяется как глобальная, вместе со структур- ной переменной disc. Такой тип определения требуется в тех случаях, когда функция возвращает структу- ру.

Листинг 11.4. Возвращение структуры.

/*CD4.c*/ struct CD

main()

{

char name[20];

char description[40]; char category[12]; float cost; int number;

} disc, getdisc();

{

disc = getdisc();

puts("Введена следующая информация о диске:\n\n"); printf("Название: %s\n", disc.name); printf("Описание: %s\n", disc.description); printf("Категория: %s\n", disc.category);

printf("Цена: %6.2f\n", disc.cost); printf("Номер п/п: %d\n", disc.number);

}

struct CD getdisc()

{

struct CD inputdisc;

puts("Введите сведения о диске\n\n"); printf("Введите название: "); gets(inputdisc.name); printf("Введите описание: "); gets(inputdisc.description); printf("Введите категорию: "); gets(inputdisc.category); printf("Введите цену: ");

scanf("%f", &inputdiscdics.cost); printf("Введите номер ячейки: "); scanf("%d", &inputdisc.number); return(inputdisc);

}

Указатели

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

К переменной можно обратиться одним из двух способов. Используя имя переменной, вы обращаетесь к значению переменной, которое хранится в памяти. Используя оператор получения адреса (&), вы обра- щаетесь к тому адресу в памяти, где хранится значение переменной.

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

tax = 35;

вы, тем самым, вносите в элементы памяти некое значение. По адресу, соответствующему области памяти, отведенной для переменной tax, будет содержаться значение 35. Можно вывести на дисплей адрес эле- мента памяти переменной, если использовать оператор получения адреса. Инструкция

printf("%d", &tax);

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

&tax = 25;

будет ошибочной.

Указателем называется переменная, которая содержит значение адреса элемента памяти, где хранится значение другой переменной. Если значение переменной tax хранится в элементе, расположенном по ад- ресу 21260, то и указатель на переменную tax будет иметь значение 21260*.

Чтобы создать указатель, используйте синтаксис, показанный на рис.11.9. Начать следует с определения типа данных, которые хранятся в элементах памяти, определяемых указателем. Символ «звездочка» гово- рит компилятору, что вы создаете указатель. В конце указывается имя переменной. Например, инструкция

int *taxptr;

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

float *net;

Рис. 11.9. Определение указателя

создаст указатель с именем net, который будет содержать адрес переменной типа float.

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

taxptr = &tax;

В этих инструкциях мы помещаем адрес, по которому содержится значение переменной tax, в переменную taxptr (рис.11.10). Если значение переменной tax хранится по адресу 21260, переменная taxptr получит значение 21260.

* Здесь имеется в виду только смещение переменной относительно начала сегмента данных (при работе в больших моделях памяти). Чтобы отобразить на экране полный адрес, нужно воспользоваться указателем формата "%p", а не "%d", как в приведенном примере. (Прим.перев.)

Рис. 11.10. Присваивание адреса указателю

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

main()

{

int *taxptr; int tax;

taxptr = &tax; tax = 35;

printf("Значение переменной tax равно %d\n", tax); printf("Указатель переменной tax

имеет значение %d\n", taxptr);

}

Эта программа выведет на дисплей сообщения: