Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lec_cvv.docx
Скачиваний:
8
Добавлен:
01.06.2015
Размер:
110.86 Кб
Скачать

Int argc; /*argc – число командных аргументов*/

char *argv[]; /*argv – указатель на массив указателей; последний адресует командные аргументы*/

{

while(-argc>0) printf((argc>1)?”%s”:”%s\n”, *++argv); /*если argc=1, то цикл while не выполняется, так как argv[0] – ссылка на саму команду, если argc>1, то последовательно печатается каждая символьная строка – командный аргумент*/

/*в функции printf форматный аргумент может быть выражением; здесь использована тернарная операция “?:”*/

}

Результат выполнения программы:

D:\> p28 программа

Программа

/*Программа Р29. Использование вариантных параметров из командной строки*/

#include<stdio.h>

main(argc, argv)

int argc;

char *argv[];

{ if(argv[1][0]==’-‘&&argv[1][1]==’r’)

{while(-argc>1) printf((argc>2)?”%s”:”%s\n”, *(argv+argc));}

/*argv[1][0] – это первый (нулевой) символ строки, на которую указывает argv[1]. Если после знака “-“ введена буква “r”, то вывод аргументов-слов осуществляется в обратном порядке*/

else if(argv[1][0]==’-‘&&argv[1][1]==’s’){++argv; /*приращение argv, так как аргументы из командной строки необходимо выводить, начиная с 3-го*/

while(-argc>1) printf((argc>2)?”%s ”:”%s\n”, *++argv);} /*если после знака “-“ записана буква “s”, то вывод аргументов происходит в прямом порядке*/

else puts(“неверна команда”); /*если после знака “-“ не записаны буквы “r” или “s”, то команда неверная*/

}

Результат работы программы:

D:\>p29 –r Профессор Петров

Петров Профессор

D:\>p29 –s Профессор Петров

Профессор Петров

4.7.Указатели на функции

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

/*Программа Р30. Указатели на функции*/

#include<stdio.h>

main(){

int f1(), f2(), a;

puts(“главная функция: введите значение а”);

scanf(“%d”, &a);

f1(f2, a);

puts(“главная функция после вызова f1”);

}

f1(f2, a) /*функция f1 использует функцию f2 в качестве аргумента*/

int (*f2)(), a; /*объявление целой переменной а и указание того, что f2 – адрес функции, возвращающей целое значение; первая пара скобок необходима*/

{ int b, c;

printf(“функция 1; a=$d; введите значение b\n”, a);

scanf(“%d”, &b);

(*f2)(b, &c); /*Обращение к функции f2 по указателю f2; здесь f2 – указатель, а *f2 сама функция, в качестве второго параметра функции *f2 передается адрес переменной с. Следует обратить внимание на требуемый порядок расстановки скобок*/

printf(“функция 1 после вызова f2; d=%d\n”, c);

}

f2(b, d) /*функция f2, у которой параметр d – это адрес переменной с в функции f1*/

int b, *d; /*переменную d необходимо объявить как указатель*/

{ printf(“функция 2; b=%d; введите значение b\n”, b);

scanf(“%d”, d);

}

Результаты работы программы Р30:

Главная функция: введите значение а

5

Функция 1; введите значение b

7

Функция 2; b=7; введите значение d

10

Функция 1 после вызова f2; d=10

Главная функция после вызова f1

В объявлении int(*f2)() f2 – указатель на функцию, возвращающую целое значение. Первая пара скобок необходима, без них int *f2() означало бы, что f2 возвращает указатель на целое значение, а это совсем не одно и то же.

5.СТРУКТУРЫ

Запись – это объединение объектов (переменных, массивов, указателей, других записей и т.д.), возможно различных типов, в одну группу, имеющую единственное имя. Для описания записи используется ключевое слово struct, за которым идет ее тип и далее список элементов, заключенный в фигурные скобки. В примере программы Р35 вводится запись типа computer.

/*Программа Р35. Демонстрация записи*/

#include<stdio.h>

struct computer {int mem;

int sp;

char model[20];} /*объявление записи типа computer, состоящей из 3-х элементов: mem, sp, model*/

struct computer pibm={8, 10, “ПЭВМ”}; /*объявление и инициализация pibm типа computer*/

main(){

printf(“персональная ЭВМ %s\n\n”, pibm.model);

printf(“объем оперативной памяти – %d Мбайт\n”, pibm.mem);

printf(“производительность – %d млн. операций в секунду\n”, pibm.sp);

/*вывод на экран значений элементов записи*/

}

Результаты выполнения программы Р35:

Персональная ЭВМ ПЭВМ

Объем оперативной памяти – 8 Мбайт

Производительность – 10 млн. операций в секунду

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

struct computer{…} a, b, c;

При этом выделяется соответствующая память. Описание без последующего списка элементов не выделяет никакой памяти; оно просто задает форму записи. Введенное имя типа позже можно использовать для объявления записи. При необходимости записи можно инициализировать, помещая за объявлением список начальных значений элементов. Элементы отдельной записи именуются следующим образом: имя записи, элемент, например, pibm.mem (программа Р35).

Записи можно вкладывать одна в другую, что показано в программа Р36:

/*Программа Р36. Демонстрация вложенных записей*/

#include<stdio.h>

struct date {int day;

int month;

int year;}

struct person { char fam[20];

char im[20];

char ot[20];

struct date f1; }; /*одним из элементов записи является запись f1 типа date*/

main(){

struct person ind1; /*объявление переменной ind1 типа person*/

printf(“укажите фамилию, имя, отчество, день, месяц и год рождения гражданина ind1\n”);

scanf(“%s%s%s%d%d%d”, ind1.fam, ind1.im, ind1.ot, &ind1.f1.day, &ind1.f1.month, &ind1.f1.year ); /*ввод сведений о гражданине*/

printf(“\nсведения о гражданине ind1\n”);

printf(“фамилия, имя, отчество: %s%s%s\n”, ind1.fam, ind1.im, ind1.ot);

printf(“год рождения – %d\n”, ind1.f1.year);

printf(“месяц рождения – %d\n”, ind1.f1.month);

printf(“день рождения – %d\n”, ind1.f1.day); /*вывод сведений о гражданине*/

Результаты выполнения программы Р36:

Укажите фамилию, имя, отчество, день, месяц и год рождения гражданина ind1

Сидоров

Петр

Иванович

3

5

1978

Сведения о гражданине ind1

Фамилия, имя, отчество: Сидоров Петр Иванович

Год рождения – 1978

Месяц рождения – 5

День рождения – 3

Записи можно использовать в виде элементов массива. Соответствующий пример дан в программе Р38:

/*Программа Р38. Массивы записей*/

#include<stdio.h>

struct computer {int mem, sp; char model[20];} pibm[10]; /*объявление записи типа computer, объявление массива pibm типа computer*/

main(){

int i, j, k, priz;

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

printf(“введите сведения о ПЭВМ %d и признак (0 – конец; \nдругая цифра – продолжение)\n”, i);

printf(“модель ПЭВМ – ”);

scanf(“%s”, pibm[i].model);

printf(“объем оперативной памяти –”);

scanf(“%d”, &pibm[i].mem);

printf(“производительность –“);

scanf(“%d”, &pibm[i].sp);

printf(“признак –”);

scanf(“%d”, &priz); k=i;

if(!priz) break; } /*!priz – операция отрицания признака priz; break – выход из цикла если priz=0*/

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

printf(“\nо какой ПЭВМ вы хотите получить сведения?\n (введите номер от 0 до 9)\n”);

scanf(“%d”, &j);

if(j>k){printf(“нет сведений об этой ПЭВМ\n”); continue;};

printf(“персональная ЭВМ %s\n”, pibm[j].model);

printf(“объем оперативной памяти – %d Мбайт\n”, pibm[j].mem);

printf(“производительность – %d млн. операций в секунду\n”, pibm[j].sp);

printf(“признак –”);

scanf(“%d”, &priz);

if(!priz) break; }

/*ввод сведений о ПЭВМ и занесение в массив pibm записей типа computer (первый цикл for); вывод на экран сведений о ПЭВМ (второй цикл for)*/

}

Результат выполнения программы:

Введите сведения о ПЭВМ 0 и признак (0 – конец; другая цифра – продолжение)

Модель ПЭВМ – IBM 486

Объем оперативной памяти – 8

Производительность – 10

Признак – 1

Введите сведения о ПЭВМ 1 и признак (0 – конец; другая цифра – продолжение)

Модель ПЭВМ – IBM 486

Объем оперативной памяти – 8

Производительность – 10

Признак – 0

О какой ПЭВМ вы хотите получить сведения?

(введите номер от 0 до 9)

1

Персональная ЭВМ IBM 486

Объем оперативной памяти – 8 Мбайт

Производительность – 10 млн. операций в секунду

Признак – 0

5.2.Указатели на записи

Унарная операция & позволяет взять адрес записи. Соответствующие указатели можно передавать функциям, использовать в других записях и т.д. Пример использования указателя на запись и передачи его в функцию в виде параметра приведен в программе Р37. Она позволяет по времени года и номеру дня в году определить число и название месяца. В случае задания неправильного номера дня (например, 366 в невисокосном году) выдается сообщение.

/*Программа Р37. Демонстрация указателей на записи и функции*/

#include<stdio.h>

Static int dofm[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};

static char *name[]={“января”,”февраля”,”марта”,”апреля”,”мая”,”июня”,”июля”,”августа”,”сентября”,”октября”,”ноября”,”декабря”};

struct date{int d, m, y, yd; char *mname;} md; /*объявление записи типа date и переменной md типа date*/

main(){ /*main() и monthd() находятся в одном файле*/

puts(“введите номер года и номер дня года”);

scanf(“%d%d”, &md.y, &md.yd);

monthd(&md); /*обращение к функции monthd(), выдающей номер месяца и число по номеру дня; функции monthd() передается адрес записи md*/

md.mname=name[md.m]; /*элементу (указателю) md.mname записи md присваивается адрес выбранного месяца; здесь md.m – номер месяца, полученный из функции monthd()*/

printf(“\t%d\t%s”, md.d, md.mname); /*вывод числа и названия месяца по номеру дня в году*/

}

monthd(md)

struct date *md; /*описание указателя md на запись типа date*/

{int i, v; /*переменная v=1 для високосного года и v=0 в противном случае*/

v=md->y&4==md->y&100!=0::md->y&400==0; /*определение значения v; последовательность символов md->y эквивалентна (*md).y; т.е. выбирается элемент из записи *md (здесь md – указатель на запись, а *md – сама запись)*/

if(md->yd>365+v) {puts(“введен неправильный код дня”); exit(); } /*exit завершает программу*/

md->d=md->yd; /*сначала номер дня месяца принимается равным введенному номеру дня года*/

for(i=0; md->d>dofm[v][i]; i++) md->-=dofm[v][i]; /*из числа md->d последовательно вычитаются дни текущих месяцев до тех пор, пока очередное (уменьшенное) значение md-> не будет меньше или равно числу дней в очередном месяце*/

md->m=1; /*md->m принимает значение номера последнего месяца в цикле for*/

}

Результаты работы программы Р37:

Введите номер года и номер дня года

1988

193

11 июля

В программе Р37 использованы новые обозначения вида md->d, где md – указатель (адрес соответствующей записи). Чтобы выбрать элемент d записи, следовало бы записать (*md).d (md – адрес, *md – сама запись, скобки нужны, так как точка имеет более высокий, чем *, приоритет). Операция -> тоже выбирает элемент записи. Другими словами, формы md->d и (*md).d полностью эквивалентны. Программа Р39 дает пример записей с указателями на себя.

/*Программа Р39. Записи с указателями на себя*/

#include<stdio.h> /*все функции находятся в одном файле*/

struct der{char *w; /*w – указатель на слово*/

int c; /*c – число вхождений слова*/

struct der *l; /*l – указатель на левое поддерево*/

struct der *r; }; /*r – указатель на правое поддерево*/

main(){

struct der *kr, *dr(); /*kr – указатель на запись der; *dr – функция, возвращающая указатель на запись der */

int i; /*i – число введенных слов*/

char word[40][21]; /*word – массив введенных слов*/

kr=NULL; /*сначала назначается: адрес корня kr дерева равен NULL (указатель ни на что)*/

l=0;

puts(“длина вводимых слов не должна превышать \n 20 символов”);

do{puts(“ввести очередное слово”);

scanf(“%s”, word[i]); /*ввод очередного слова*/

kr=dr(kr, word[i]);}; /*указатель kr получает значение адреса записи со словом word[0] (с первым введенным словом)*/

while(word[i++][0]!=”0”); /*цикл будет выполняться до тех пор, пока первый символ слова word[i] не нуль*/

drpr(kr); /*вывод дерева на экран в виде упорядоченного списка*/

}

struct der *dr(kr, word); /*функция *dr возвращает адрес очередной записи со словом word*/

struct der *kr; /*kr – указатель типа der*/

char *word;

{ struct der *calloc(); /*библиотечная функция calloc() возвращает указатель на запись типа der*/

int sr; /*sr – результат сравнения слов*/

int sravnenie();

if(kr==NULL){ /*поступило новое слово*/

kr=calloc(l, sizeof(struct der)); /*kr получает значение начального адреса области памяти, в которой можно разместить одну запись типа der*/

kr->w=word; /*kr->w получает адрес прочитанного слова*/

kr->c=1; /*число вхождений слова word равно единице*/

kr->l=kr->r=NULL;} /*указатели на левое и правое поддеревья получают значение NULL*/

else if((sr=sravnenie(word, kr->w))==0) kr->c++; /*увеличивается число вхождений слова word*/

else if(sr<0) kr->1=dr(kr->1, word); /*выбирается левое поддерево*/

else kr->r=dr(kr->r, word); /*выбирается правое поддерево*/

return(kr); /*возвращение указателя kr*/

sravnenie(s1, s2)

char *s1, *s2;

{ for(;*s1==*s2; s1++, s2++) if(*s1==”\0”) return(0); return(*s1-*s2);}

drpr(kr) /*рекурсивная печать построенного дерева*/

struct der *kr;

{if(kr!=NULL) {drkr(kr->l); /*выбирается левое поддерево*/

printf(“слово –%s, количество повторений %d\n”, kr->w, kr->c);

drkr(kr->r);} /*выбирается правое поддерево*/

}

Результаты работы программы Р39:

Длина вводимых слов не должна превышать

20 символов

Ввести очередное слово

Петров

Ввести очередное слово

Иванов

Ввести очередное слово

Сидоров

Ввести очередное слово

Иванов

Ввести очередное слово

Борисов

Ввести очередное слово

0

Слово – Борисов, количество повторений – 1

Слово – Иванов, количество повторений – 2

Слово – Петров, количество повторений – 1

Слово – Сидоров, количество повторений – 1

Слово – 0, количество повторений – 1

В программе вводится последовательность слов (например, фамилии сотрудников некоторой фирмы). Программа выполняет лексикографическое упорядочение слов и выдачу полученного списка на экран. Упорядочение осуществляется с помощью структуры, называемой двоичным деревом. Различным словам списка соответствуют различные вершины дерева, каждая из которых в программе Р39 является записью, включающей: указатель на слово списка; число вхождений слова; указатель на левую следующую вершину; указатель на правую следующую вершину. Ни одна вершина не может иметь более 2-х следующих, но может иметь одну или вообще не иметь. Дерево строится так, что левая следующая вершина содержит слова меньше данного, а правая – больше данного.

5.3.Поля и смеси

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

#include<stdio.h>

struct{ unsigned a:1; unsigned b:1; unsigned y:1; unsigned c:2; } f; /*объявление переменной f, содержащей 3 одноразрядных и одно 2-хразрядное поле (число, следующее за двоеточием, задает количество разрядов в поле) */

main(){

int i;

printf(“размер f= %d байта\n”, sizeof(f));

f.a=f.b=1; /*в поля f.a и f.b записываются единицы*/

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

f.y=f.a&&f.b; /*вычисляется коньюнкция f.y переменных f.a и f.b*/

printf(“цикл %d; f.y=%d\n”, i, f.y);

f.b=0;} /*в поле f.b записывается ноль*/

f.c=f.a+!f.b; /*арифметическое сложение значения f.a (оно равно единице) и отрицание значения f.b (отрицание нуля тоже равно единице); в результате f.c=2*/

printf(“f.c=%d”, f.c);

}

Результаты работы программы Р40:

Размер f=2 байта

Цикл 0; f.y=1

Цикл 1; f.y=0

f.c=2

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

Смесь – это некоторая переменная, которая может хранить (в разное время) объекты различного типа и размера. В результате появляется возможность работы в одной и той же области памяти с данными различного вида. Для описания смеси используется ключевое слово union, а соответствующий синтаксис аналогичен записям.

Программа Р41 демонстрирует использование смеси:

/*Программа Р41. Демонстрация смесей*/

#include<stdio.h>

union r {int ir, float fr, char cr;} z; /*объявление смеси z типа r; переменная z достаточно велика, чтобы сохранять самый большой из 3-х приведенных типов*/

main(){

printf(“размер z=%d байта\n”, sizeof(z));

printf(“введите значение z.ir\n”);

scanf(“%d”, &z.ir);

printf(“значение ir=%d\n”, z.ir);

printf(“введите значение z.fr\n”);

scanf(“%f”, &z.fr);

printf(“значение fr=%f\n”, z.fr);

printf(“введите значение z.cr\n”);

scanf(“%1s”, &z.cr);

printf(“значение cr=%c\n”, z.cr);

}

Результаты работы программы Р41:

Размер z=4 байта

Введите значение z.ir

7

Значение ir=7

Введите значение z.fr

8.3456678

Значение fr=8.345668

Введите значение z.cr

P

Значение cr=p

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]