Купить
 
 
Жанр: Учеба

Хрестоматия по программированию на Си в Unix

страница №8

е.

А. Богатырев, 1992-95 - 91 - Си в UNIX

g : ref p() ref array of ref p() ref int
*g : p() ref array of ref p() ref int
(*g)() : ref array of ref p() ref int
*(*g)() : array of ref p() ref int
(*(*g)())[5] : ref p() ref int
*(*(*g)())[5] : p() ref int
(*(*(*g)())[5])(): ref int
*(*(*(*g)())[5])(): int
int *(*(*(*g)())[5])();

В Си невозможны функции, возвращающие массив:

proc() array of ...
а только
proc() ref array of ...

Само название типа (например, для использования в операции приведения типа) получается
вычеркиванием имени переменной (а также можно опустить размер массива):

g = ( int *(*(*(*)())[])() ) 0;

2.19. Напишите функцию strcat(d,s), приписывающую строку s к концу строки d.
Ответ:

char *strcat(d,s) register char *d, *s;
{ while( *d ) d++; /* ищем конец строки d */
while( *d++ = *s++ ); /* strcpy(d, s) */
return (d-1); /* конец строки */
}

Цикл, помеченный "strcpy" - это наиболее краткая запись операторов

do{ char c;
c = (*d = *s); s++; d++;
} while(c != '\0');

На самом деле strcat должен по стандарту возвращать свой первый аргумент, как и функция
strcpy:

char *strcat(d,s) register char *d, *s;
{ char *p = d;
while( *d ) d++;
strcpy(d, s); return p;
}

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

2.20. Напишите программу, которая объединяет и распечатывает две строки, введенные с
терминала. Для ввода строк используйте функцию gets(), а для их объединения -
strcat(). В другом варианте используйте
sprintf(result,"%s%s",s1,s2);

2.21. Модифицируйте предыдущую программу таким образом, чтобы она выдавала длину
(число символов) объединенной строки. Используйте функцию strlen(). Приведем несколько
версий реализации strlen:

/* При помощи индексации массива */

А. Богатырев, 1992-95 - 92 - Си в UNIX

int strlen(s) char s[];
{ int length = 0;
for(; s[length] != '\0'; length++);
return (length);
}
/* При помощи продвижения указателя */
int strlen(s) char *s;
{ int length;
for(length=0; *s; length++, s++);
return length;
}
/* При помощи разности указателей */
int strlen(register char *s)
{ register char *p = s;
while(*p) p++; /* ищет конец строки */
return (p - s);
}

Разность двух указателей на один и тот же тип - целое число:

если TYPE *p1, *p2;
то p2 - p1 = целое число штук TYPE
лежащих между p2 и p1
если p2 = p1 + n
то p2 - p1 = n

Эта разность может быть и отрицательной если p2 " p1, то есть p2 указывает на более
левый элемент массива.

2.22. Напишите оператор Си, который обрубает строку s до длины n букв. Ответ:

if( strlen(s) " n )
s[n] = '\0';

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

2.23. Напишите функции преобразования строки, содержащей изображение целого числа, в
само это число. В двух разных вариантах аргумент-адрес должен указывать на первый
байт строки; на последний байт. Ответ:

#define isdigit© ('0' "= (c) && (c) "= '9')

int atoi(s) register char *s;
{ register int res=0, neg=0;
for(;;s++){
switch(*s){
case ' ': case '\t': continue;
case '-': neg++;
case '+': s++;
} break;
}
while(isdigit(*s))
res = res * 10 + *s++ - '0';
return( neg ? -res : res );
}

int backatoi(s) register char *s;
{ int res=0, pow=1;
while(isdigit(*s)){

А. Богатырев, 1992-95 - 93 - Си в UNIX

res += (*s-- - '0') * pow;
pow *= 10;
}
if(*s == '-') res = -res;
return res;
}

2.24. Можно ли для занесения в массив s строки "hello" написать

char s[6]; s = "hello";
или
char s[6], d[] = "hello"; s = d;

Ответ: нет. Массивы в Си нельзя присваивать целиком. Для пересылки массива байт надо
использовать функцию strcpy(s,d). Здесь же мы пытаемся изменить адрес s (имя массива
- это адрес начала памяти, выделенной для хранения массива), сделав его равным адресу
безымянной строки "hello" (или массива d во втором случае). Этот адрес является
константой и не может быть изменен!
Заметим однако, что описание массива с инициализацией вполне допустимо:

char s[6] = "hello";
или
char s[6] = { 'h', 'e', 'l', 'l', 'o', '\0' };
или
char s[] = "hello";
или
char s[] = { "hello" };

В этом случае компилятор резервирует память для хранения массива и расписывает ее
байтами начального значения. Обратите внимание, что строка в двойных кавычках (если
ее рассматривать как массив букв) имеет длину на единицу больше, чем написано букв в
строке, поскольку в конце массива находится символ '\0' - признак конца, добавленный
компилятором. Если бы мы написали

char s[5] = "hello";

то компилятор сообщил бы об ошибке, поскольку длины массива (5) недостаточно, чтобы
разместить 6 байт. В третьей строке примера написано s[], чтобы компилятор сам посчитал
необходимую длину массива.
Наконец, возможна ситуация, когда массив больше, чем хранящаяся в нем строка.
Тогда "лишнее" место содержит какой-то мусор (в static-памяти изначально - байты \0).

char s[12] = "hello";
содержит: h e l l o \0 ? ? ? ? ? ?

В программах текстовой обработки под "длиной строки" обычно понимают количество букв
в строке НЕ считая закрывающий байт '\0'. Именно такую длину считает стандартная
функция strlen(s). Поэтому следует различать такие понятия как "(текущая) длина
строки" и "длина массива, в котором хранится строка": sizeof(s). Для написанного
выше примера эти значения равны соответственно 5 и 12.
Следует также отличать массивы от указателей:

char *sp = "bye bye";
sp = "hello";

printf("%d\n", ch);
равная адресу начала массива), а указатель (переменная, хранящая адрес некоторой
области памяти). Поскольку указатель - это переменная, то ее значение изменять
можно: в данном случае sp сначала содержала адрес безымянного массива, в котором
находится "bye bye"; затем мы занесли в sp адрес безымянного массива, хранящего

А. Богатырев, 1992-95 - 94 - Си в UNIX

строку "hello". Здесь не происходит копирования массива, а происходит просто присваивание
переменной sp нового значения адреса.
Предостережем от возможной неприятности:

char d[5]; char s[] = "abcdefgh";
strcpy(d, s);

Длины массива d просто не хватит для хранения такой длинной строки. Поскольку это
ничем не контролируется (ни компилятором, ни самой strcpy, ни вами явным образом), то
при копировании строки "избыточные" байты запишутся после массива d поверх других
данных, которые будут испорчены. Это приведет к непредсказуемым эффектам.
Некоторые возможности для контроля за длиной строк-аргументов вам дают функции
strncpy(d,s,len); strncat(d,s,len); strncmp(s1,s2,len). Они пересылают (сравнивают)
не более, чем len первых символов строки s (строк s1, s2). Посмотрите в документацию!
Напишите функцию strncmp (сравнение строк по первым len символам), посмотрев на
функцию strncpy:

char *strncpy(dst, src, n)
register char *dst, *src;
register int n;
{ char *save;
for(save=dst; --n "= 0; )
if( !(*dst++ = *src++)){
while(--n "= 0)
*dst++ = '\0';
return save;
}
return save;
}

Отметьте, что strncpy обладает одним неприятным свойством: если n "= strlen(src), то
строка dst не будет иметь на конце символа '\0', то есть будет находиться в некорректном
(не каноническом) состоянии.
Ответ:

int strncmp(register char *s1, register char *s2, register int n)
{
if(s1 == s2)
return(0);
while(--n "= 0 && *s1 == *s2++)
if(*s1++ == '\0')
return(0);
return((n " 0)? 0: (*s1 - *--s2));
}

2.25. В чем ошибка?


#include "stdio.h" /* для putchar */
char s[] = "We don't need no education";
main(){ while(*s) putchar(*s++); }

Ответ: здесь s - константа, к ней неприменима операция ++. Надо написать

char *s = "We don't need no education";

сделав s указателем на безымянный массив. Указатель уже можно изменять.

2.26. Какие из приведенных конструкций обозначают одно и то же?

А. Богатырев, 1992-95 - 95 - Си в UNIX

char a[] = ""; /* пустая строка */
char b[] = "\0";
char c = '\0';
char z[] = "ab";
char aa[] = { '\0' };
char bb[] = { '\0', '\0' };
char xx[] = { 'a', 'b' };
char zz[] = { 'a', 'b', '\0' };
char *ptr = "ab";

2.27. Найдите ошибки в описании символьной строки:

main() {
char mas[] = {'s', 'o', 'r', 't'}; /* "sort" ? */
printf("%s\n", mas);
}

Ответ: строка должна кончаться '\0' (в нашем случае printf не обнаружив символа конца
строки будет выдавать и байты, находящиеся в памяти после массива mas, т.е. мусор);
инициализированный массив не может быть автоматическим - требуется static:

main() {
static char mas[] = {'s', 'o', 'r', 't', '\0'};
}

Заметим, что

main(){ char *mas = "sort"; }

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

2.28. В чем ошибка? Программа собирается из двух файлов: a.c и b.c командой

cc a.c b.c -o ab
a.c b.c
---------------------------------------------------
int n = 2; extern int n;
char s[] = "012345678"; extern char *s;
main(){ f(){
f(); s[n] = '+';
printf("%s\n", s ); }
}

Ответ: дело в том, что типы (char *) - указатель, и char[] - массив, означают одно и
то же только при объявлении формального параметра функции:

f(char *arg){...} f(char arg[]){...}

это будет локальная переменная, содержащая указатель на char (т.е. адрес некоторого
байта в памяти). Внутри функции мы можем изменять эту переменную, например arg++.
Далее, и (char *) и char[] одинаково используются, например, оба эти типа можно
индексировать: arg[i]. Но вне функций они объявляют разные объекты! Так char *p; это
скалярная переменная, хранящая адрес (указатель):

-------- -------
p:| *--|-----"| '0' | char
-------- | '1' | char
А. Богатырев, 1992-95 - 96 - Си в UNIX

тогда как char a[20]; это адрес начала массива (а вовсе не переменная):

-------
a:| '0' | char
| '1' | char
В нашем примере в файле b.c мы объявили внешний массив s как переменную. В результате
компилятор будет интерпретировать начало массива s как переменную, содержащую
указатель на char.

-------
s:| '0' | \ это будет воспринято как
| '1' | / адрес других данных.
| '2' |
И индексироваться будет уже ЭТОТ адрес! Результат - обращение по несуществующему
адресу. То, что написано у нас, эквивалентно

char s[] = "012345678";
char **ss = s; /* s - как бы "массив указателей" */
/* первые байты s интерпретируются как указатель: */
char *p = ss[0];
p[2] = '+';

Мы же должны были объявить в b.c

extern char s[]; /* размер указывать не требуется */

Вот еще один аналогичный пример, который пояснит вам, что происходит (а заодно покажет
порядок байтов в long). Пример выполнялся на IBM PC 80386, на которой

sizeof(char *) = sizeof(long) = 4

a.c b.c
---------------------------------------------------
char s[20] = {1,2,3,4}; extern char *s;
main(){ f(){
/*печать указателя как long */
f(); printf( "%08lX\n", s );
} }

печатается 04030201.

2.29. Что напечатает программа?

static char str1[ ] = "abc";
static char str2[4];

strcpy( str2, str1 );
/* можно ли написать str2 = str1; ? */

printf( str1 == str2 ? "равно":"не равно" );

Как надо правильно сравнивать строки? Что на самом деле сравнивается в данном примере?

Ответ: сравниваются адреса массивов, хранящих строки. Так

А. Богатырев, 1992-95 - 97 - Си в UNIX

char str1[2];
char str2[2];
main(){
printf( str1 " str2 ? """:""");
}

печатает "<, а если написать

char str2[2];
char str1[2];

то напечатается ">.

2.30. Напишите программу, спрашивающую ваше имя до тех пор, пока вы его правильно не
введете. Для сравнения строк используйте функцию strcmp() (ее реализация есть в главе
"Мобильность").

2.31. Какие значения возвращает функция strcmp() в следующей программе?


#include "stdio.h"
main() {
printf("%d\n", strcmp("abc", "abc")); /* 0 */
printf("%d\n", strcmp("ab" , "abc")); /* -99 */
printf("%d\n", strcmp("abd", "abc")); /* 1 */
printf("%d\n", strcmp("abc", "abd")); /* -1 */
printf("%d\n", strcmp("abc", "abe")); /* -2 */
}

2.32. В качестве итога предыдущих задач: помните, что в Си строки (а не адреса) надо
сравнивать как

if( strcmp("abc", "bcd") " 0) ... ;
if( strcmp("abc", "bcd") == 0) ... ;
вместо
if( "abc" " "bcd" ) ... ;
if( "abc" == "bcd" ) ... ;

и присваивать как

char d[80], s[80];
strcpy( d, s ); вместо d = s;

2.33. Напишите программу, которая сортирует по алфавиту и печатает следующие ключевые
слова языка Си:

int char double long
for while if

2.34. Вопрос не совсем про строки, скорее про цикл: чем плоха конструкция?

char s[] = "You're a smart boy, now shut up.";
int i, len;
for(i=0; i " strlen(s); i++)
putchar(s[i]);

Ответ: в соответствии с семантикой Си цикл развернется примерно в

А. Богатырев, 1992-95 - 98 - Си в UNIX

i=0;
LOOP: if( !(i " strlen(s))) goto ENDLOOP;
putchar(s[i]);
i++;
goto LOOP;
ENDLOOP: ;

Заметьте, что хотя длина строки s не меняется, strlen(s) вычисляется на КАЖДОЙ итерации
цикла, совершая лишнюю работу! Борьба с этим такова:

for(i=0, len=strlen(s); i " len; i++ )
putchar(s[i]);
или
for(i=0, len=strlen(s); len " 0; i++, --len )
putchar(s[i]);

Аналогично, в цикле

while( i " strlen(s))...;

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

2.35. Что напечатает следующая программа?

#include "stdio.h"
main(){
static char str[] = "До встречи в буфете";
char *pt;

pt = str; puts(pt); puts(++pt);
str[7] = '\0'; puts(str); puts(pt);
puts(++pt);
}

2.36. Что напечатает следующая программа?

main() {
static char name[] = "Константин";
char *pt;
pt = name + strlen(name);
while(--pt "= name)
puts(pt);
}

2.37. Что напечатает следующая программа?

char str1[] = "abcdef";
char str2[] = "xyz";
main(){
register char *a, *b;
a = str1; b = str2;
while( *b )
*a++ = *b++;
printf( "str=%s a=%s\n", str1, a );

a = str1; b = str2;

А. Богатырев, 1992-95 - 99 - Си в UNIX

while( *b )
*++a = *b++;
printf( "str=%s a=%s\n", str1, a );
}

Ответ:

str=xyzdef a=def
str=xxyzef a=zef

2.38. Что печатает программа?

char *s;
for(s = "Ситроен"; *s; s+= 2){
putchar(s[0]); if(!s[1]) break;
}
putchar('\n');

2.39. Что напечатает программа? Рассмотрите продвижение указателя s, указателей -
элементов массива strs[]. Разберитесь с порядком выполнения операций. В каких случаях
++ изменяет указатель, а в каких - букву в строке? Нарисуйте себе картинку, изображающую
состояние указателей - она поможет вам распутать эти спагетти. Уделите разбору
этого примера достаточное время!

#include "stdio.h" /* определение NULL */
/* Латинский алфавит: abcdefghijklmnopqrstuvwxyz */
char *strs[] = {
"abcd","ABCD","0fpx","159",
"hello","-gop","A1479",NULL
};
main(){
char c, **s = strs, *p;
c = *++*s; printf("#1 %d %c %s\n", s-strs, c, *s);
c = **++s; printf("#2 %d %c %s\n", s-strs, c, *s);
c = **s++; printf("#3 %d %c %s\n", s-strs, c, *s);
c = ++**s; printf("#4 %d %c %s\n", s-strs, c, *s);
c = (**s)++; printf("#5 %d %c %s\n", s-strs, c, *s);
c = ++*++*s; printf("#6 %d %c %s\n", s-strs, c, *s);
c = *++*s++; printf("#7 %d %c %s %s\n",
s-strs, c, *s, strs[2]);
c = ++*++*s++; printf("#8 %d %c %s %s\n",
s-strs, c, *s, strs[3]);
c = ++*++*++s; printf("#9 %d %c %s\n", s-strs,c,*s);
c = ++**s++; printf("#10 %d %c %s\n",s-strs,c,*s);
p = *s; c = ++*(*s)++;
printf("#11 %d %c %s %s %s\n",s-strs,c,*s,strs[6],p);
c = ++*((*s)++); printf("#12 %d %c %s %s\n",
s-strs, c, *s, strs[6]);
c = (*++(*s))++; printf("#13 %d %c %s %s\n",
s-strs, c, *s, strs[6]);
for(s=strs; *s; s++)
printf("strs[%d]=\"%s\"\n", s-strs, *s);
putchar('\n');
}

Печатается:

А. Богатырев, 1992-95 - 100 - Си в UNIX

#1 0 b bcd strs[0]="bcd"
#2 1 A ABCD strs[1]="ABCD"
#3 2 A 0fpx strs[2]="px"
#4 2 1 1fpx strs[3]="69"
#5 2 1 2fpx strs[4]="hello"
#6 2 g gpx strs[5]="iop"
#7 3 p 159 px strs[6]="89"
#8 4 6 hello 69
#9 5 h hop
#10 6 i A1479
#11 6 B 1479 1479 B1479
#12 6 2 479 479
#13 6 7 89 89

Учтите, что конструкция

char *strs[1] = { "hello" };

означает, что в strs[0] содержится указатель на начальный байт безымянного массива,
содержащего строку "hello". Этот указатель можно изменять! Попробуйте составить еще
подобные примеры из *, ++, ().

2.40. Что печатает программа?

char str[25] = "Hi, ";
char *f(char **s){ int cnt;
for(cnt=0; **s != '\0'; (*s)++, ++cnt);
return("ny" + (cnt && (*s)[-1] == ' ') + (!cnt));
}
void main(void){ char *s = str;
if( *f(&s) == 'y') strcat(s, "dude");
else strcat(s, " dude");
printf("%s\n", str);
}

Что она напечатает, если задать

char str[25]="Hi,"; или char str[25]="";

2.41. В чем состоит ошибка? (Любимая ошибка начинающих)

main(){
char *buf; /* или char buf[]; */
gets( buf );
printf( "%s\n", buf );
}

Ответ: память под строку buf не выделена, указатель buf не проинициализирован и смотрит
неизвестно куда. Надо было писать например так:

char buf[80];
или
char mem[80], *buf = mem;

Обратите на этот пример особое внимание, поскольку, описав указатель (но никуда его
не направив), новички успокаиваются, не заботясь о выделении памяти для хранения данных.
Указатель должен указывать на ЧТО-ТО, в чем можно хранить данные, а не "висеть",
указывая "пальцем в небо"! Запись информации по "висячему" указателю разрушает память
программы и приводит к скорому (но часто не немедленному и потому таинственному)
краху.

А. Богатырев, 1992-95 - 101 - Си в UNIX

Вот программа, которая также использует неинициализированный указатель. На
машине SPARCstation 20 эта программа убивается операционной системой с диагностикой
"Segmentation fault" (SIGSEGV). Это как раз и значит обращение по указателю, указывающему
"пальцем в небо".

main(){
int *iptr;
int ival = *iptr;

printf("%d\n", ival);
}

2.42. Для получения строки "Life is life" написана программа:

main(){
char buf[ 60 ];
strcat( buf, "Life " );
strcat( buf, "is " );
strcat( buf, "life" );
printf( "%s\n", buf );
}

Что окажется в массиве buf?
Ответ: в начале массива окажется мусор, поскольку автоматический массив не инициализируется
байтами '\0', а функция strcat() приписывает строки к концу строки. Для исправления
можно написать

*buf = '\0';

перед первым strcat()-ом, либо вместо первого strcat()-а написать
strcpy( buf, "Life " );

2.43. Составьте макроопределение copystr(s1, s2) для копирования строки s2 в строку
s1.

2.44. Составьте макроопределение lenstr(s) для вычисления длины строки.
Многие современные компиляторы сами обращаются с подобными короткими (1-3 оператора)
стандартными функциями как с макросами, то есть при обращении к ним генерят не
вызов функции, а подставляют текст ее тела в место обращения. Это делает объектный
код несколько "толще", но зато быстрее. В расширенных диалектах Си и в Си++ компилятору
можно предложить обращаться так и с вашей функцией - для этого функцию следует
объявить как inline (такие функции называются еще "intrinsic").

2.45. Составьте рекурсивную и нерекурсивную версии программы инвертирования (зеркального
отображения) строки:

abcdef --" fedcba.

2.46. Составьте функцию index(s, t), возвращающую номер первого вхождения символа t
в строку s; если символ t в строку не входит, функция возвращает -1.
Перепишите эту функцию с указателями, чтобы она возвращала указатель на первое
вхождение символа. Если символ в строке отсутствует - выдавать NULL. В UNIX System-V
такая функция называется strchr. Вот возможный ответ:

char *strchr(s, c) register char *s, c;
{ while(*s && *s != c) s++;
return *s == c ? s : NULL;
}

А. Богатырев, 1992-95 - 102 - Си в UNIX

Заметьте, что p=strchr(s,'\0'); выдает указатель на конец строки. Вот пример использования:


extern char *strchr();
char *s = "abcd/efgh/ijklm";
char *p = strchr(s, '/');
printf("%s\n", p==NULL ? "буквы / нет" : p);
if(p) printf("Индекс вхождения = s[%d]\n", p - s );

2.47. Напишите функцию strrchr(), указывающую на последнее вхождение символа.
Ответ:

char *strrchr(s, c) register char *s, c;
{ char *last = NULL;
do if(*s == c) last = s; while(*s++);
return last;
}

Вот пример ее использования:

extern char *strrchr();
char p[] = "wsh"; /* эталон */
main(argc, argv) char *argv[];{
char *s = argv[1]; /* проверяемое имя */
/* попробуйте вызывать
* a.out csh
* a.out /bin/csh
* a.out wsh
* a.out /usr/local/bin/wsh
*/
char *base =
(base = strrchr(s, '/')) ? base+1 : s;
if( !strcmp(p, base))
printf("Да, это %s\n" , p);
else printf("Нет, это %s\n", base);

/* еще более изощренный вариант: */
if( !strcmp(p,(base=strrchr(s,'/')) ? ++base :
(base=s))
) printf("Yes %s\n", p);
else printf("No %s\n", base);
}

2.48. Напишите макрос substr(to,from,n,len) который записывает в to кусок строки
from начиная с n-ой позиции и длиной len. Используйте стандартную функцию strncpy.
Ответ:

#define substr(to, from, n, len) strncpy(to, from+n, len)

или более корректная функция:

А. Богатырев, 1992-95 - 103 - Си в UNIX

char *substr(to, from, n, len) char *to, *from;
{
int lfrom = strlen(from);
if(n " 0 ){ len += n; n = 0; }
if(n "= lfrom || len "= 0)
*to = '\0'; /* пустая строка */
else{
/* длина остатка строки: */
if(len " lfrom-n) len = lfrom - n;
strncpy(to, from+n, len);
to[len] = '\0';
}
return to;
}

2.49. Напишите функцию, проверяющую, оканчивается ли строка на ".abc", и если нет -
приписывающую ".abc" к концу. Если же строка уже имеет такое окончание - ничего не
делать. Эта функция полезна для генерации имен файлов с заданным расширением. Сделайте
расширение аргументом функции.
Для сравнения конца строки s со строкой p следует использовать:

int ls = strlen(s), lp = strlen(p);
if(ls "= lp && !strcmp(s+ls-lp, p)) ...совпали...;

2.50. Напишите функции вставки символа c в указанную позицию строки (с раздвижкой
строки) и удаления символа в заданной позиции (со сдвижкой строки). Строка должна
изменяться "на месте", т.е. никуда не копируясь. Ответ:

/* удаление */
char delete(s, at) register char *s;
{
char c;
s += at; if((c = *s) == '\0') return c;
while( s[0] = s[1] ) s++;
return c;
}
/* либо просто strcpy(s+at, s+at+1); */

/* вставка */
insert(s, at, c) char s[], c;
{
register char *p;
s += at; p = s;
while(*p) p++; /* на конец строки */
p[1] = '\0'; /* закрыть строку */
for( ; p != s; p-- )
p[0] = p[-1];
*s = c;
}

2.51. Составьте программу удаления символа c из строки s в каждом случае, когда он
встречается.
Ответ:

А. Богатырев, 1992-95 - 104 - Си в UNIX

delc(s, c) register char *s; char c;
{
register char *p = s;
while( *s )
if( *s != c ) *p++ = *s++;
else s++;
*p = '\0'; /* не забывайте закрывать строку ! */
}

2.52. Составьте программу удаления из строки S1 каждого символа, совпадающего с
каким-либо символом строки S2.

2.53. Составьте функцию scopy(s,t), которая копирует строку s в t, при этом символы
табуляции и перевода строки должны заменяться на специальные двухсимвольные последовательности
"\n" и "\t". Используйте switch.

2.54. Составьте функцию, которая "укорачив

Список страниц

Закладка в соц.сетях

Купить

☏ Заказ рекламы: +3805044-68-872

© Ассоциация электронных библиотек Украины

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