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

Функция gets(). 7 страница

Читайте также:
  1. Castle of Indolence. 1 страница
  2. Castle of Indolence. 2 страница
  3. Castle of Indolence. 3 страница
  4. Castle of Indolence. 4 страница
  5. Castle of Indolence. 5 страница
  6. Castle of Indolence. 6 страница
  7. Castle of Indolence. 7 страница

sprintf(str, "i=%d and j=%d", i, j);

// содержимое str: "i=15 and j=15"

Эти функции очень похожи на printf и scanf, за исключением того, что они работают не с консолью, а со строковым буфером.

Хотя sprintf и sscanf довольно удобны, у них есть несколько недостатков. Во-первых, они не всегда быстро работают, во-вторых не типобезопасны. Например, если в строке формата вы укажите, что передаете два целых, а вместо этого передадите два double, ошибка обнаружится только при выполнении программы и найти ее причину будет не так-то просто.

В-третьих, доступно целое семейство функций atof, atoi, atol и itoa, ltoa. Все они очень похоже между собой. Функции из первой группы преобразуют строку в число (float, int или long) в зависимости от окончания. Функции из второй группы выполняют обратное преобразование.

Конкатенация (объединение) строк:

Есть две специальные функции:char* strcat(char* dest, const char* source)

char* strncat(char* dest, const char* source, size_t size)

Эти функции добавляют к строке, на которую указывает dest, символы из строки source. Первая версия добавляет все символы до нуль-терминатора, вторая – максимум size символов. Результирующая строка завершается нуль-терминатором.

 

52.

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

void error(char* p) { /*... */ }

void (*efct)(char*); // указатель на функцию

void f()

{

efct = &error; // efct настроен на функцию error

(*efct)("error"); // вызов error через указатель efct

}

Для вызова функции с помощью указателя (efct в нашем примере) надо вначале применить операцию косвенности к указателю - *efct. Поскольку приоритет операции вызова () выше, чем приоритет косвенности *, нельзя писать просто *efct("error"). Это будет означать *(efct("error")), что является ошибкой. По той же причине скобки нужны и при описании указателя на функцию. Однако, писать просто efct("error") можно, т.к. транслятор понимает, что efct является указателем на функцию, и создает команды, делающие вызов нужной функции.

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

void (*pf)(char*); // указатель на void(char*)

void f1(char*); // void(char*);

int f2(char*); // int(char*);

void f3(int*); // void(int*);

void f()

{

pf = &f1; // нормально

pf = &f2; // ошибка: не тот тип возвращаемого

// значения

pf = &f3; // ошибка: не тот тип параметра

(*pf)("asdf"); // нормально

(*pf)(1); // ошибка: не тот тип параметра

int i = (*pf)("qwer"); // ошибка: void присваивается int

}

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

Часто бывает удобнее обозначить тип указателя на функцию именем, чем все время использовать достаточно сложную запись. Например:

typedef int (*SIG_TYP)(int); // из <signal.h>

typedef void (SIG_ARG_TYP)(int);

SIG_TYP signal(int, SIG_ARG_TYP);

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

typedef void (*PF)();

PF edit_ops[] = { // команды редактора

&cut, &paste, &snarf, &search

};

PF file_ops[] = { // управление файлом

&open, &reshape, &close, &write

};

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

Выбор происходит нажатием клавиши мыши:

PF* button2 = edit_ops;

PF* button3 = file_ops;

 

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

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

Если пользователь выбрал позицию меню, которая определяется, например, как позиция 3 для клавиши 2, то соответствующая команда реализуется вызовом:

(*button2[3])();

Чтобы полностью оценить мощность конструкции указатель на функцию, стоит попытаться написать программу без нее. Меню можно изменять в динамике, если добавлять новые функции в таблицу команд.

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

typedef int (*CFT)(void*,void*);

void sort(void* base, unsigned n, unsigned int sz, CFT cmp)

/*

Сортировка вектора "base" из n элементов

в возрастающем порядке;

используется функция сравнения, на которую указывает cmp.

Размер элементов равен "sz".

Алгоритм очень неэффективный: сортировка пузырьковым методом

*/

{

for (int i=0; i<n-1; i++)

for (int j=n-1; i<j; j--) {

char* pj = (char*)base+j*sz; // b[j]

char* pj1 = pj - sz; // b[j-1]

if ((*cmp)(pj,pj1) < 0) {

// поменять местами b[j] и b[j-1]

for (int k = 0; k<sz; k++) {

char temp = pj[k];

pj[k] = pj1[k];

pj1[k] = temp;

}

}

}

}

В подпрограмме sort неизвестен тип сортируемых объектов; известно только их число (размер массива), размер каждого элемента и функция, которая может сравнивать объекты. Мы выбрали для функции sort() такой же заголовок, как у qsort() - стандартной функции сортировки из библиотеки С. Эту функцию используют настоящие программы.

Покажем, как с помощью sort() можно отсортировать таблицу с такой структурой:

struct user {

char* name; // имя

char* id; // пароль

int dept; // отдел

};

typedef user* Puser;

user heads[] = {

"Ritchie D.M.", "dmr", 11271,

"Sethi R.", "ravi", 11272,

"SZYmanski T.G.", "tgs", 11273,

"Schryer N.L.", "nls", 11274,

"Schryer N.L.", "nls", 11275

"Kernighan B.W.", "bwk", 11276

};

void print_id(Puser v, int n)

{

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

cout << v[i].name << '\t'

<< v[i].id << '\t'

<< v[i].dept << '\n';

}

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

int cmp1(const void* p, const void* q)

// сравнение строк, содержащих имена

{

return strcmp(Puser(p)->name, Puser(q)->name);

}

 

int cmp2(const void* p, const void* q)

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

{

return Puser(p)->dept - Puser(q)->dept;

}

Следующая программа сортирует и печатает результат:

int main()

{

sort(heads,6,sizeof(user), cmp1);

print_id(heads,6); // в алфавитном порядке

cout << "\n";

sort(heads,6,sizeof(user),cmp2);

print_id(heads,6); // по номерам отделов

}

Допустима операция взятия адреса и для функции-подстановки, и для перегруженной функции ($$R.13.3).

Отметим, что неявное преобразование указателя на что-то в указатель типа void* не выполняется для параметра функции, вызываемой через указатель на нее. Поэтому функцию

int cmp3(const mytype*, const mytype*);

нельзя использовать в качестве параметра для sort(). Поступив иначе, мы нарушаем заданное в описании условие, что cmp3() должна вызываться с параметрами типа mytype*. Если вы специально хотите нарушить это условие, то должны использовать явное преобразование типа.

 

Любая программа на языке Си состоит из одной или более функций, причём ровно одна из них обязательно должна называться "main" ("главная"). Программа всегда начинает выполняться с главной функции main. имеется возможность выбирать имена для всех создаваемых функций, кроме той, с которой начинается выполнение программы.

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

Функция main, с которой начинается выполнение программы на языке программирования С, может быть определена с параметрами, которые передаются из внешнего окружения, например, из командной строки. Во внешнем окружении действуют свои правила представления данных, а точнее, все данные представляются в виде строк символов. Для передачи этих строк в функцию main используются два параметра, первый параметр служит для передачи числа передаваемых строк, второй для передачи самих строк. Общепринятые (но не обязательные) имена этих параметров argc и argv. Параметр argc имеет тип int, его значение формируется из анализа командной строки и равно количеству слов в командной строке, включая и имя вызываемой программы (под словом понимается любой текст не содержащий символа пробел). Параметр argv это массив указателей на строки, каждая из которых содержит одно слово из командной строки. Если слово должно содержать символ пробел, то при записи его в командную строку оно должно быть заключено в кавычки.

Функция main может иметь и третий параметр, который принято называть argp, и который служит для передачи в функцию main параметров операционной системы (среды) в которой выполняется программа на языке программирования С.

Заголовок функции main имеет вид:

int main (int argc, char *argv[], char *argp[])

Если, например, командная строка программы на языке программирования С имеет вид:

A:\>cprog working 'C program' 1

то аргументы argc, argv, argp представляются в памяти как показано в схеме на рис.1.

argc [ 4 ]

argv [ ]--> [ ]--> [A:\cprog.exe\0]

[ ]--> [working\0]

[ ]--> [C program\0]

[ ]--> [1\0]

[NULL]

argp [ ]--> [ ]--> [path=A:\;C:\\0]

[ ]--> [lib=D:\LIB\0]

[ ]--> [include=D:\INCLUDE\0]

[ ]--> [conspec=C:\COMMAND.COM\]

[NULL]

Рис.1. Схема размещения параметров командной строки

 

54.

Разбор аргументов в главной функции и их использование

Иногда при запуске программы бывает полезно передать ей какую-либо информацию. Обычно такая информация передается функции main() с помощью аргументов командной строки. Аргумент командной строки — это информация, которая вводится в командной строке операционной системы вслед за именем программы. Чтобы принять аргументы командной строки, используются два специальных встроенных аргумента: argc и argv. Параметр argc содержит количество аргументов в командной строке и является целым числом, причем он всегда не меньше 1, потому что первым аргументом считается имя программы. А параметр argv является указателем на массив указателей на строки. В этом массиве каждый элемент указывает на какой-либо аргумент командной строки. Все аргументы командной строки являются строковыми, поэтому преобразование каких бы то ни было чисел в нужный двоичный формат должно быть предусмотрено в программе при ее разработке.

Вот простой пример использования аргумента командной строки. На экран выводятся слово Привет и ваше имя, которое надо указать в виде аргумента командной строки.

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char *argv[]) {

if(argc!=2) {

printf("Вы забыли ввести свое имя.\n");

exit(1); }

printf("Привет %s", argv[1]);

return 0; }

Очень важно правильно объявлять argv. Вот как это делают чаще всего:

char *argv[]; Пустые квадратные скобки указывают на то, что у массива неопределенная длина. Теперь получить доступ к отдельным аргументам можно с помощью индексации массива argv. Например, argv[0] указывает на первую символьную строку, которой всегда является имя программы; argv[1] указывает на первый аргумент и так далее.

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

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

 

55.

Функции ввода-вывода: классификация функций, ввод-вывод символов и строк.

 

56.

Функции ввода-вывода: классификация функций, ввод-вывод символов и строк

Функции форматированного ввода-вывода

printf – производит форматированный вывод в stdout.

int printf(const char *format [,argument,…]);

scanf – выполняет форматированный вывод из потока stdin.

int scanf(const char *format [,adress,…]);

fprintf – посылает форматированный вывод в поток stream.

int fprintf(FILE *stream, const char *format [,argument,…]);

fscanf – выполняет форматированный ввод из потока stream.

int fscanf(FILE *stream, const char *format [,adress,…]);

sprintf – производит форматированный вывод в сстроку buffer.

int sprintf(char *buffer, const char *format [,argument,…]);

sscanf – выполняет форматированный ввод из строки buffer.

Int sscanf(const char *buffer, const char *format [,adress,…]);

Богатый ассортимент средств управления форматом позволяет легко создавать таблицы, графики или отчеты. Функциями, выполняющими этот вывод являются printf() - для стандартного потока вывода stdout, и fprintf() – для любого потока. Функция fprintf() имеет вид:
fprintf(поток_вывода, “формат”, перем_1, перем_2,…);
Работает она аналогично printf() и выводит данные в указанный поток вывода.
Для форматированного ввода используются функции scanf() и fscanf().
Для преобразования текстовой строки можно использовать sscanf(). Она работает аналогично fscanf(), но данные берет из сроки, а не из файла.

Для работы со стандартными потоками в режиме форматного ввода-вывода определены две функции:

printf() - форматный вывод;

scanf() - форматный ввод.

Прототип функции printf() имеет вид:

int printf(const char *format,...);

При обращении к функции printf() возможны две формы задания первого параметра:

int printf (*форматная строка, список_аргументов);

int printf (указателъ_на_форматную_строку,. список_аргументов);

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

Возвращаемое значение функции printf() - число напечатанных символов; а в случае ошибки - отрицательное число.

Форматная_строка ограничена двойными кавычками и может включать произвольный текст, управляющие символы и спецификации преобразования данных. Текст и управляющие символы из форматной строки просто копируются в выходной поток. Форматная строка обычно размещается в списке фактических параметров функции, что соответствует первому варианту вызова функции printf(). Второй вариант предполагает, что первый фактический параметр - это указатель типа char *, a сама форматная строка определена в программе как обычная строковая константа или переменная.

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

Если аргументов недостаточно для данной форматной строки, то результат зависит от реализации (от операционной системы и от системы программирования). Если аргументов больше, чем указано в форматной строке, "лишние" аргументы игнорируются. Гарантируется, что при любом количестве параметров и любом их типе после выполнения функций printf() дальнейшее выполнение программы будет корректным.

 

56.

Форматированный ввод и вывод. Богатый ассортимент средств управления форматом позволяет легко создавать таблицы, графики или отчеты. Функциями, выполняющими этот вывод являются printf() - для стандартного потока вывода stdout, и fprintf() – для любого потока. Функция fprintf() имеет вид: fprintf(поток_вывода, “формат”, перем_1, перем_2,…); Работает она аналогично printf() и выводит данные в указанный поток вывода. Для форматированного ввода используются функции scanf() и fscanf(). Для преобразования текстовой строки можно использовать sscanf(). Она работает аналогично fscanf(), но данные берет из сроки, а не из файла. Потоки cin, cout, cerr. В языке С++ имеется другая библиотека ввода/вывода, определяемая заголовочным файлом iostream.h. Ввод/вывод в ней определяется набором специальных классов. Аналогами потоков stdin, stdout и stderr являются cin, cout и cerr. Они открываются автоматически при запуске программы. Операции выделения >> и вставки <<. Для ввода/вывода с помощью указанных потоков используются специальным образом определенные операции “занести в поток” и “получить из потока”, << и <<. Операция >> выделяет данные из входного потока и помещает в указанные переменные, а операция << помещает значения указанных переменных в поток.Приведем пример использования потока stdin и потока cin: scanf(“%d%lf%c”,&ivalue,&dvalue,&cvalue); cin>>ivalue>>dvalue>>cvalue; Аналогично для вывода: printf(“Integer:%d double: %lf”,ivalue,dvalue); cout<<”Integer:”<<ivalue<<” double:”<<dvalue;

 

57.

Важное отличие языка СИ от других языков (PL1, FORTRAN, и др.) является отсутствие принципа умолчания, что приводит к необходимости объявления всех переменных используемых в программе явно вместе с указанием соответствующих им типов.

Объявления переменной имеет следующий формат:

[спецафикатор-класа-памяти] спецификатор-типа

описатель [=инициатор] [,описатель [= инициатор] ]...

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

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

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

Спецификатор класса памяти - определяется одним из четырех ключевых слов языка СИ: auto, extern, register, static, и указывает,каким образом будет распределяться память под объявляемую переменную, с одной стороны, а с другой, область видимости этой переменной, т.е., из каких частей программы можно к ней обратиться.


Дата добавления: 2015-07-26; просмотров: 68 | Нарушение авторских прав


Читайте в этой же книге: Структура программы. | Создание библиотеки | Функция gets(). 1 страница | Функция gets(). 2 страница | Функция gets(). 3 страница | Функция gets(). 4 страница | Функция gets(). 5 страница | Указатели | Инициализация данных | Структуры |
<== предыдущая страница | следующая страница ==>
Функция gets(). 6 страница| Целый тип данных

mybiblioteka.su - 2015-2024 год. (0.023 сек.)