Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Практикум по программированию на языке Си

..pdf
Скачиваний:
25
Добавлен:
12.11.2023
Размер:
3.53 Mб
Скачать

ЗАДАЧА 09-15. Определите строку, состоящую из каких-либо строчных и прописных букв. Определите вторую строку-шаблон, содержащую несколько прописных букв. Используя библиотечные функции, определите вхождения букв из строки-шаблона в первую строку без учета регистров. Напечатайте найденные буквы и номера их позиций.

Алгоритм решения уже не нов для нас. Определим два указателя c1, c2 типа char *. Настроим с1 на начало "исследуемой" строки. В цикле выполним поиск в строке, адресуемой с1, символов из строки шаблона. Указателю с2 будем присваивать начало найденного "сегмента" строки. Если c2==NULL, – конец обработки. Иначе *c2 – искомый символ. Вычитая из с2 адрес начала строки, определим его позицию в строке. Присвоив с1 значение с2+1, переходим к следующей итерации цикла. Текст программы:

/* 09_15.c – поиск заданных букв в строке (без учета регистра) */

#include <stdio.h> #include <string.h> int main()

{

char mixture[]="asd fFSSFKhg"; char stamp[]="AEF";

char * c1, * c2; int counter=0; strupr(mixture);

printf("stamp=%s\n",stamp);

printf("\nmixture=%s\n",mixture);

c1=mixture; while((c2=strpbrk(c1,stamp)) != NULL)

{printf("\n%c - %d",*c2,c2-mixture); c1=c2+1;

}

}

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

stamp=AEF

mixture=ASD FFSSFKHG

371

A - 0

F - 5

F - 6

F - 9

Результаты исполнения программы очевидны. Отметим только, что исходная строка, помещенная в символьный массив mixture[] при инициализации, изменена функцией strupr().

ЭКСПЕРИМЕНТ. Инициализируйте массивы mixture[] и stamp[] из рассмотренной программы строками из прописных и строчных русских букв. Выполните программу и убедитесь, что после исполнения функции strupr() строка mixture не изменилась.

Объяснение – функция strupr() может использоваться только для преобразования символов латинского алфавита. (Смотрите текст программы в файле 09_15_1.с.)

Примечание. Функция strupr() входит в библиотеки промышленных компиляторов, но не стандартизована (ее нет в Стандарте языка Си). При необходимости ее можно написать, используя стандартный макрос toupper(), определенный в ctype.h. Этот макрос преобразует строчную латинскую букву в прописную.

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

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

372

Рис. 9.1. Таблица результатов измерений

Для "упаковки" последовательности значений в символьную строку удобно использовать библиотечную функцию

int sprintf(char * s, const char * format, …);

Первый параметр – указатель на символьный массив, куда в виде последовательности символьных "изображений" помещаются значения следующих аргументов функции. Форматная строка, адресуемая указателем format, задает форму представления каждого из изображений аргументов. При окончании записи функция sprintf() автоматически добавляет в символьный массив символ конца строки '\0'. Функция sprintf() возвращает количество символов, записанных в символьный массив без учета символа конца строки '\0'.

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

int sscanf(char * s, const char * format, …);

Здесь s – указатель на строку-источник информации; format – указатель на форматную строку; многоточием обозначены аргументы, соответствующие спецификациям преобразования форматной строки. В соответствии со спецификациями форматной строки функция sscanf() приписывает своим необязательным аргументам значения, изображенные в символьном виде в строке, адресованной параметром s.

Функция sscanf() возвращает значение EOF, если при какомлибо из преобразований последовательности символов в значении аргумента обнаружено несоответствие. В случае удачного окончания "чтения" функция sscanf() возвращает количество прочитанных зна-

373

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

Предположим, что характеристики процесса (см. табл. на рис. 9.1), за которым ведется наблюдение, находятся в следующих преде-

лах:

0 < A < 2·10-5;

–0.008 < B < 0.008;

–10-8 < C < 10-12.

ЗАДАЧА 09-16. Напишите две функции и основную программу для обработки "строк-контейнеров" со сведениями об описанном гипотетическом процессе. Первая функция должна формировать строку со сведениями об отсчете. Вторая функция должна выводить на экран таблицу результатов "наблюдения" за процессом. В основной программе вводится количество отсчетов, для которых должна быть построена таблица.

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

Для формирования псевдослучайных вещественных чисел в диапазоне от xmin до xmax определим вспомогательную, но весьма полезную функцию:

/* myRand.c - псевдослучайные числа в выбранном диапазоне */

#ifndef MYRAND #define MYRAND

#include <stdlib.h> /* RAND_MAX, rand(), srand() */ double myRand(double xmin, double xmax)

{long nn; double result; nn=rand();

result=xmin+(double)nn*(xmax-xmin)/RAND_MAX; return result;

}

#endif

В теле функции MyRand() используем библиотечную функцию rand(), возвращающую псевдослучайные целые числа в диапазоне от 0 до RAND_MAX. Настройку функции rand() выполняют с помощью вспомогательной библиотечной функции srand(unsigned int),

374

вызывая последнюю в основной программе. Обратите внимание на препроцессорную защиту текста функции от повторных включений (см. тему 3, задача 03_09).

Для формирования строки с имитируемыми значениями характеристик процесса введем функцию:

// measure.c - формирование строки таблицы отсчетов

#include <stdio.h> #include "myRand.c" #define SIZE 600

#include <stdlib.h> /* RAND_MAX, rand(), srand() */ char * measure()

{

static char pack[SIZE]; double a,b,c; a=myRand(0.0, 2e5); b=myRand(-0.008, 0.008); c=myRand(-1e-8, 1e-12);

sprintf(pack,"%d %f %e",(int)a,b,c); return pack;

}

В ней определен статический символьный массив pack[], достаточно большой для представления формируемых значений характеристик. Обратите внимание, что значения, заносимые в pack[], отделяются друг от друга пробелами, что предусмотрено форматной строкой функции sprintf(). Для формирования значений в теле функции выполняются обращения к функции myRand().

Функция печати таблицы может быть такой:

/* process.c - функция печати строки таблицы */ #ifndef PROCESS

#define PROCESS #include <stdio.h>

int process(char * package)

{

int a, i=0; double b, c;

static int count = 0; if (count == 0)

{ while (i++<44) putchar('-');

375

printf("\n|count|

A

|

B

|"

"

C

 

|\n");

 

 

while (i-- > 1) putchar('-'); putchar('\n');

}

count++;

if (sscanf(package,"%d %lf %le",&a,&b,&c) == EOF) return EOF;

printf("|%4d |%7d |%10f |%14e |\n",count,a,b,c); return 0;

}

#endif

Функция возвращает либо EOF при ошибках, либо 0 – при успешном завершении. В теле функции статическая переменная static int count=0; "управляет" печатью "шапки" таблицы и служит счетчиком номеров ее строк. Из строки, адресованной параметром package, функция sscanf() считывает разделенные пробелами значения характеристик процесса и присваивает их переменным, адресованным ее аргументами &a, &b, &c. Точно подобранные размеры полей в форматных строках функции printf() позволяют вывести аккуратную таблицу. Текст основной программы:

/* 09_16.c - таблица отсчетов "наблюдений" */ #include <stdio.h>

#define SIZE 600

#include <stdlib.h> // RAND_MAX, rand(), srand() #include "measure.c"

#include "process.c" int main ()

{

char * res;

int i, number=0; srand(RAND_MAX/2);

printf("The number of counts: "); scanf("%d",&number);

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

{res = measure();

if (process(res) == EOF) return 0;

}

return 0;

}

376

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

The number of counts: 5<ENTER>

--------------------------------------------

|count| A | B | C |

--------------------------------------------

|

1

|

42754

| -0.001723 | -5.982058e-09 |

|

2

|

67719

|

0.004739

| -2.990152e-09

|

|

3

| 164038 |

0.005955

| -4.094309e-09

|

|

4

|

87020

|

0.001373

|

-1.876521e-09

|

|

5

|

81810

| -0.007785

|

-2.875584e-09

|

В функции main() вводится количество желаемых строк таблицы (number), и в цикле последовательно вызываются функции формирования (measure) и распаковки с печатью (process) строк, адресуемых указателем char * res.

Обращение к функции srand() настраивает "генератор" псевдослучайных чисел rand(), вызываемый в myRand(). Остальное очевидно из текста и результатов программы.

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

9.4. Аргументы функции main() и работа со строками

ЗАДАЧА 09-17. Напечатайте значения аргументов, передаваемых программе в командной строке.

/* 09_17.c - массив указателей на строки – аргумент main() */

#include <stdio.h>

int main (int number, char * arg[])

{

int i;

for (i=0; i<number; i++) printf("arg[%d]=%s\n",i,arg[i]); return 0;

}

377

Если после трансляции 09_17.с исполнимый модуль получил название test.exe, то командная строка запуска будет, например, такой:

C:\practic\progs\09>test.exe 1 22 aaa bbbb <ENTER>

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

arg[0]=c:/practic/progs/09/test.exe

arg[1]=1

arg[2]=22

arg[3]=aaa

arg[4]=bbbb

Напомним, что аргументы в командной строке отделяются друг от друга пробельными символами. Их количество передается в функцию main() с помощью первого из ее параметров (int number в нашем примере). Все аргументы воспринимаются как строки и адресуются элементами массива-параметра (char * arg[] в нашем примере). Элемент arg[0] адресует строку, представляющую полный адрес (полный путь к размещению) исполняемой программы.

ЗАДАЧА 09-18. Введите в командной строке последовательность вещественных чисел. В программе создайте динамический массив с элементами типа double и занесите в него введенные числа. Напечатайте их значения в обратном порядке. Для решения задачи используйте функцию atof().

Так как первый параметр "передает" в функцию main() количество аргументов из командной строки, то с помощью функции calloc() легко создать динамический массив с нужным количеством элементов типа double. Если динамический массив адресовать указателем double * array, а массив-параметр функции main() обозначить char * str[], то выполнить преобразование строки символов, адресованной указателем str[], в вещественное число можно таким образом:

378

array[i]=atof(str[i]);

Программа, решающая задачу:

/* 09_18.c - Числовые значения в командной строке */ #include <stdio.h>

#include <stdlib.h>

int main(int k, char * str[])

{

int i;

double * array;

array=(double *)calloc(k,sizeof(double)); if (array == NULL)

{puts("Error of calloc()!"); exit(0);

}

for (i=1; i<k; i++) array[i]=atof(str[i]);

for (i=k-1; i>0; i--) printf("\t%f",array[i]);

}

Запуск программы из командной строки:

C:\...>test.exe 12.4 3.14159 0.27172e1<ENTER>

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

2.717200

3.141590

12.400000

Для преобразования символьного представления числа из строки во внутренний код соответствующего типа кроме функций atof(), atoi(), atol() можно применять уже использованную в программе 09_16.с (точнее, в функции process()) функцию форматного чтения из строки (описана в stdio.h):

int sscanf(const char *s, const char * format, …);

Обращение к этой функции в нашей программе может быть таким:

379

sscanf(str[i], "%lf", &array[i]);

Изображение числа из строки (из аргумента функции main()) str[i] преобразуется по формату со спецификацией преобразования %lf во внутренний код числа типа double и присваивается элементу array[i] вещественного массива. Текст программы в файле

09_18_1.с.

ЗАДАЧА 09-19. Напечатайте все строки стандартного входного потока, содержащие слово (термин), заданное в качестве аргумента в командной строке при запуске программы.

Решение задачи предусматривает следующие шаги, выполняемые в цикле:

Прочитать строку входного потока Искать в строке заданный термин Если термин найден в строке

Печатать строку

Для поиска в строке термина используем библиотечную функцию с прототипом

char * strstr(const char * str1, const char str2);

Функция strstr() возвращает указатель на тот элемент строки str1, с которого начинается подстрока, совпадающая с str2. При отсутствии в строке str1 такой подстроки возвращается значение

NULL.

Для чтения строки из входного потока напишем функцию readLine(), возвращающую указатель на динамический символьный массив, содержащий непустую строку, прочитанную из входного потока. При достижении конца файла, на который настроен стандартный входной поток, функция readLine() должна вернуть значение NULL.

/* readLine.c - функция чтения строки входного потока */

#include <stdio.h>

380