Упражнение 7.5. Перепишите основанную на постфиксной записи программу калькулятора из главы 4 таким образом, чтобы для ввода и преобразования чисел она использовала scanf и/или sscanf.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXOP 100 /* макс. размер операнда или оператора */
#define NUMBER '0' /* признак числа */
int getop (char *);
void push (double);
double pop (void);
/* калькулятор с обратной польской записью */
int main()
{
int op;
double op2;
char s[MAXOP];
while ((op = scanf("%s", s)) && op != EOF) {
switch (getop(s)) {
case NUMBER:
push (atof(s));
break;
case '+':
push (pop() + pop());
break;
case '*':
push (pop() * pop());
break;
case '-':
op2 = pop();
push (pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push (pop() / op2);
else
printf("ошибка: деление на нуль\n");
break;
default:
printf("ошибка: неизвестная операция %s\n", s);
break;
}
}
printf("\t%.8g\n", pop());
return 0;
}
/* getop: получает следующий оператор или операнд */
int getop(char *s)
{
if (!isdigit(s[0]) && s[0] != '.')
return s[0]; /* не число */
else
return NUMBER;
}
Упражнение 7.6. Напишите программу, сравнивающую два файла и печатающую первую строку, в которой они различаются.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 100
/* filecmp: сравнение содержимого двух файлов */
int main(int argc, char *argv[])
{
int i = 0;
FILE *fp1, *fp2;
char *s1, *s2, line1[MAXLINE], line2[MAXLINE], *prog = argv[0]; /* имя программы */
if (argc != 3) {
fprintf(stderr, "usage: filecmp file1 file2\n");
exit(1);
}
if ((fp1 = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "s\n", prog, argv[1]);
exit(1);
}
if ((fp2 = fopen(argv[2], "r")) == NULL) {
fprintf(stderr, "s\n", prog, argv[2]);
exit(1);
}
if (!strcmp(argv[1], argv[2])) { /* не одинаковы ли файлы? */
printf("no differences\n");
exit(0);
}
while ((s1 = fgets(line1, MAXLINE, fp1)) != NULL && (s2 = fgets(line2, MAXLINE, fp2)) != NULL) {
i++;
if (strcmp(line1, line2)) {
printf("\ndifference:\n");
printf("line s: %s", i, argv[1], s1);
printf("line s: %s", i, argv[2], s2);
exit(0);
}
}
/* если один из файлов закончился раньше другого */
if (s1 && !s2) {
printf("\ndifference:\n");
printf("line s: %s", i, argv[1], s1);
printf("EOF in %s\n", argv[2]);
}
else if (!s1 && s2) {
printf("\ndifference:\n");
printf("EOF in %s\n", argv[1]);
printf("line s: %s", i, argv[2], s2);
}
else
printf("no differences\n");
exit(0);
}
Упражнение 7.7. Модифицируйте программу поиска по образцу из главы 5 таким образом, чтобы она брала текст из множества именованных файлов, а если имен файлов в аргументах нет, то из стандартного ввода. Следует ли печатать имя файла, в котором найдена подходящая строка?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1000
int except = 0, number = 0, found = 0;
void finder(char *, FILE *, int);
/* find: поиск строк по образцу из командной строки */
int main(int argc, char *argv[])
{
char *pattern, *prog = argv[0];
FILE *inp;
int c, t;
while (--argc > 0 && (*++argv)[0] == '-')
while ((c = *++argv[0]))
switch (c) {
case 'x':
except = 1;
break;
case 'n':
number = 1;
break;
default:
fprintf(stderr, "find: неверный параметр %c\n", c);
argc = 0;
found = -1;
break;
}
if (argc < 1) {
fprintf(stderr, "usage: find -x -n pattern\n");
exit(1);
}
pattern = *argv;
if (!--argc) {
finder(pattern, stdin, MAXLINE);
exit(0);
}
while (argc-- && (inp = fopen(*++argv, "r")) != NULL) {
finder(pattern, inp, MAXLINE);
}
if (!argc) {
fprintf(stderr, "s\n", prog, *argv);
exit(1);
}
return found;
}
/* finder: поиск по образцу pattern в файле input */
void finder(char *pattern, FILE *input, int maxline) {
long lineno = 0;
char line[MAXLINE], *p;
while ((p = fgets(line, MAXLINE, input)) != NULL) {
lineno++;
if ((strstr(line, pattern) != NULL) != except) {
if (number)
printf("%ld:", lineno);
printf("%s", line);
found++;
}
}
}
Упражнение 7.8. Напишите программу, печатающую несколько файлов. Каждый файл должен начинаться с новой страницы, предваряться заголовком и иметь свою нумерацию страниц.
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 1000
#define PAGELEN 15
void fprinter(FILE *, int);
/* fileprint: печать файлов, имена которых заданы в командной строке */
int main(int argc, char *argv[])
{
char *prog = argv[0];
FILE *inp;
if (argc == 1) {
fprintf(stderr, "usage: fileprint file1, file2,...\n");
exit(1);
}
while (--argc) {
if ((inp = fopen(*++argv, "r")) != NULL) {
printf("-------- begin of file %s --------\n", *argv);
fprinter(inp, MAXLINE);
printf("--------- end of file %s ---------\n", *argv);
}
else {
fprintf(stderr, "s\n", prog, *argv);
exit(1);
}
}
return 0;
}
/* fprinter: печать файла input */
void fprinter(FILE *input, int maxline) {
long t, lineno = 0;
int pageno = 1;
char line[MAXLINE], *p;
printf("-%d-\n", pageno);
while ((p = fgets(line, MAXLINE, input)) != NULL) {
if (lineno++ < PAGELEN)
printf("%s", line);
else {
lineno = 0;
printf("-%d-\n", ++pageno);
}
}
if ((t = PAGELEN - lineno) > 0)
while (--t)
printf("\n");
}
Упражнение 7.9. Реализуя функции вроде isupper, можно экономить либо память, либо время. Напишите оба варианта функции.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#define my_isupper3(c) (c >= 'A' && c <= 'Z')
int my_isupper1(char );
int my_isupper2(char );
int main(void)
{
int i, count, num = 20000000;
double t1, t2;
char line[20] = "My sample String";
t1 = clock();
while (--num)
for (i=0; line[i]; i++)
if (my_isupper3(line[i]))
count++;
t2 = (clock() - t1)/CLOCKS_PER_SEC;
printf("%lf\n", t2);
return 0;
}
int my_isupper1(char c) {
return (c >= 'A' && c <= 'Z');
}
int my_isupper2(char c) {
return (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ",c) != NULL);
}
Упражнение 1.10. Напишите программу, копирующую вводимые символы в выходной поток с заменой символа табуляции на \t, символа забоя на \b и каждой обратной наклонной черты на \\. Это сделает видимыми все символы табуляции и забоя.
#include <stdio.h>
int main()
{
int c;
while ((c = getchar()) != EOF)
if (c == '')
printf("\\");
else if (c == '\t')
printf("t");
else if (c == '\b')
printf("b");
else
putchar(c);
Упражнение 1.12. Напишите программу, которая печатает содержимое своего ввода, помещая по одному слову на каждой строке.
#include <stdio.h>
#define IN 1 /* внутри слова */
#define OUT 0 /* вне слова */
/* вывод слов в новой строке */
int main()
{
int c, state;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n' || c == '\t'){
state = OUT;
putchar('\n');
}
else if (state == OUT) {
state = IN;
putchar(c);
}
else
putchar(c);
}
return 0;
}
Упражнение 1.18. Напишите программу, которая будет в каждой вводимой строке заменять стоящие подряд символы пробелов и табуляций на один пробел и удалять пустые строки.
Упражнение 1.19. Напишите функцию reverse(s), размещающую символы в строке s в обратном порядке. Примените ее при написании программы, которая каждую вводимую строку располагает в обратном порядке.
Упражнение 1.20. Напишите программу detab, заменяющую символы табуляции во вводимом тексте нужным числом пробелов (до следующего “стопа” табуляции). Предполагается, что “стопы” табуляции расставлены на фиксированном расстоянии друг от друга, скажем, через n позиций. Как лучше задавать n -- в виде значения переменной или в виде именованной константы?
/* detab: преобразует символы табуляции 'from' в заданное
* число пробелов 'to' */
void detab(char to[], char from[])
{
int i, j, k;
i = j = 0;
while ((to[j] = from[i]) != '\0') {
if (to[j] == 't')
for (k = 0; k < TABSIZE; ++k, ++j)
to[j] = ' ';
else
++j;
++i;
}
to[j] = '\0';
}
Упражнение 1.21. Напишите программу entab, заменяющую строки из пробелов минимальным числом табуляций и пробелов таким образом, чтобы вид напечатанного текста не изменился. Используйте те же “стопы” табуляции, что и в detab. В случае, когда для выхода на очередной “стоп” годится один пробел, что лучше -- пробел или табуляция?
/* entab: преобразует символы пробелов 'from' в заданное
* число пробелов и табуляций 'to' */
void entab(char to[], char from[])
{
int i, j, k, ns, nt, c, m;
i = j = ns = nt = 0;
while ((c = from[i]) != '\0') {
if (c == ' ')
++ns;
else if (ns > 0) {
nt = ns/(TABSIZE-1);
for (m = 0; m < nt; ++m, ++j)
to[j] = '\t';
for (k = 0; k < ns-nt*(TABSIZE-1)-(nt-1); ++k, ++j)
to[j] = ' ';
to[j] = c;
ns = 0;
++j;
}
else {
to[j] = c;
++j;
}
++i;
}
to[j] = '\0';
}