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


Массивы, строки, указатели. Хрестоматия по программированию на Си в Unix


Раз уж речь зашла о функции strdup (кстати, это стандартная функция), приведем еще одну функцию для сохранения строк.

char *savefromto(register char *from, char *upto) { char *ptr, *s; if((ptr = (char *) malloc(upto - from + 1)) == NULL) return NULL; for(s = ptr; from < upto; from++) *s++ = *from; *s = '\0'; return ptr; }

Сам символ (*upto) не сохраняется, а заменяется на '\0'.

Упрощенный аналог функции printf.

/* * Машинно - независимый printf() (упрощенный вариант).

* printf - Форматный Вывод. */ #include <stdio.h>

#include <ctype.h>

#include <varargs.h>

#include <errno.h>

#include <string.h>

extern int errno; /* код системной ошибки, формат %m */ /* чтение значения числа */ #define GETN(n,fmt) \ n = 0; \ while(isdigit(*fmt)){ \ n = n*10 + (*fmt - '0'); \ fmt++; \ } void myprintf(fmt, va_alist) register char *fmt; va_dcl { va_list ap; char c, *s; int i; int width, /* минимальная ширина поля */ prec, /* макс. длина данного */ sign, /* выравнивание: 1 - вправо, -1 - влево */ zero, /* ширина поля начинается с 0 */ glong; /* требуется длинное целое */ va_start(ap); for(;;){ while((c = *fmt++) != '%'){ if( c == '\0' ) goto out; putchar(c); } sign = 1; zero = 0; glong = 0; if(*fmt == '-'){ sign = (-1); fmt++; } if(*fmt == '0'){ zero = 1; fmt++; } if(*fmt == '*'){ width = va_arg(ap, int); if(width < 0){ width = -width; sign = -sign; } fmt++; }else{ GETN(width, fmt); } width *= sign; if(*fmt == '.'){ if(*++fmt == '*'){ prec = va_arg(ap, int); fmt++; }else{ GETN(prec, fmt); } }else prec = (-1); /* произвольно */ if( *fmt == 'l' ){ glong = 1; fmt++; } switch(c = *fmt++){ case 'c': putchar(va_arg(ap, int)); break; case 's': prStr(width, prec, va_arg(ap, char *)); break; case 'm': prStr(width, prec, strerror(errno)); break; /* strerror преобразует код ошибки в строку-расшифровку */ case 'u': prUnsigned(width, glong ? va_arg(ap, unsigned long) : (unsigned long) va_arg(ap, unsigned int), 10 /* base */, zero); break; case 'd': prInteger(width, glong ? va_arg(ap, long) : (long) va_arg(ap, int), 10 /* base */, zero); break; case 'o': prUnsigned(width, glong ? va_arg(ap, unsigned long) : (unsigned long) va_arg(ap, unsigned int), 8 /* base */, zero); break; case 'x': prUnsigned(width, glong ? va_arg(ap, unsigned long) : (unsigned long) va_arg(ap, unsigned int), 16 /* base */, zero); break; case 'X': prUnsigned(width, glong ? va_arg(ap, unsigned long) : (unsigned long) va_arg(ap, unsigned int), -16 /* base */, zero); break; case 'b': prUnsigned(width, glong ? va_arg(ap, unsigned long) : (unsigned long) va_arg(ap, unsigned int), 2 /* base */, zero); break; case 'a': /* address */ prUnsigned(width, (long) (char *) va_arg(ap, char *), 16 /* base */, zero); break; case 'A': /* address */ prUnsigned(width, (long) (char *) va_arg(ap, char *), -16 /* base */, zero); break; case 'r': prRoman(width, prec, va_arg(ap, int)); break; case '%': putchar('%'); break; default: putchar(c); break; } } out: va_end(ap); } /* --------------------------------------------------------- */ int strnlen(s, maxlen) char *s; { register n; for( n=0; *s && n < maxlen; n++, s++ ); return n; } /* Печать строки */ static prStr(width, prec, s) char *s; { int ln; /* сколько символов выводить */ int toLeft = 0; /* к какому краю прижимать */ if(s == NULL){ pr( "(NULL)", 6); return; } /* Измерить длину и обрубить длинную строку. * Дело в том, что строка может не иметь \0 на конце, тогда * strlen(s) может привести к обращению в запрещенные адреса */ ln = (prec > 0 ? strnlen(s, prec) : strlen(s)); /* ширина поля */ if( ! width ) width = (prec > 0 ? prec : ln); if( width < 0){ width = -width; toLeft = 1; } if( width > ln){ /* дополнить поле пробелами */ if(toLeft){ pr(s, ln); prSpace(width - ln, ' '); } else { prSpace(width - ln, ' '); pr(s, ln); } } else { pr(s, ln); } } /* Печать строки длиной l */ static pr(s, ln) register char *s; register ln; { for( ; ln > 0 ; ln-- ) putchar( *s++ ); } /* Печать n символов c */ static prSpace(n, c) register n; char c;{ for( ; n > 0 ; n-- ) putchar( c ); } /* --------------------------------------------------------- */ static char *ds; /* Римские цифры */ static prRoman(w,p,n){ char bd[60]; ds = bd; if( n < 0 ){ n = -n; *ds++ = '-'; } prRdig(n,6); *ds = '\0'; prStr(w, p, bd); } static prRdig(n, d){ if( !n ) return; if( d ) prRdig( n/10, d - 2); tack(n%10, d); } static tack(n, d){ static char im[] = " MDCLXVI"; /* ..1000 500 100 50 10 5 1 */ if( !n ) return; if( 1 <= n && n <= 3 ){ repeat(n, im[d+2]); return; } if( n == 4 ) *ds++ = im[d+2]; if( n == 4 n == 5 ){ *ds++ = im[d+1]; return; } if( 6 <= n && n <= 8 ){ *ds++ = im[d+1]; repeat(n - 5, im[d+2] ); return; } /* n == 9 */ *ds++ = im[d+2]; *ds++ = im[d]; } static repeat(n, c) char c; { while( n-- > 0 ) *ds++ = c; } /* --------------------------------------------------------- */ static char aChar = 'A'; static prInteger(w, n, base, zero) long n; { /* преобразуем число в строку */ char bd[128]; int neg = 0; /* < 0 */ if( n < 0 ){ neg = 1; n = -n; } if( base < 0 ){ base = -base; aChar = 'A'; } else { aChar = 'a'; } ds = bd; prUDig( n, base ); *ds = '\0'; /* Теперь печатаем строку */ prIntStr( bd, w, zero, neg ); } static prUnsigned(w, n, base, zero) unsigned long n; { char bd[128]; if( base < 0 ){ base = -base; aChar = 'A'; } else { aChar = 'a'; } ds = bd; prUDig( n, base ); *ds = '\0'; /* Теперь печатаем строку */ prIntStr( bd, w, zero, 0 ); } static prUDig( n, base ) unsigned long n; { unsigned long aSign; if((aSign = n/base ) > 0 ) prUDig( aSign, base ); aSign = n % base; *ds++ = (aSign < 10 ? '0' + aSign : aChar + (aSign - 10)); } static prIntStr( s, width, zero, neg ) char *s; { int ln; /* сколько символов выводить */ int toLeft = 0; /* к какому краю прижимать */ ln = strlen(s); /* длина строки s */ /* Ширина поля: вычислить, если не указано явно */ if( ! width ){ width = ln; /* ширина поля */ if( neg ) width++; /* 1 символ для минуса */ } if( width < 0 ){ width = -width; toLeft = 1; } if( ! neg ){ /* Положительное число */ if(width > ln){ if(toLeft){ pr(s, ln); prSpace(width - ln, ' '); } else { prSpace(width - ln, zero ? '0' : ' '); pr(s, ln); } } else { pr(s, ln); } }else{ /* Отрицательное число */ if(width > ln){ /* Надо заполнять оставшуюся часть поля */ width -- ; /* width содержит одну позицию для минуса */ if(toLeft){ putchar('-'); pr(s, ln); prSpace(width - ln, ' '); } else{ if( ! zero ){ prSpace(width - ln, ' '); putchar('-'); pr(s,ln); } else { putchar('-'); prSpace(width - ln, '0'); pr(s, ln); } } } else { putchar('-'); pr(s, ln); } } } /* --------------------------------------------------------- */ main(){ int i, n; static char s[] = "Hello, world!\n"; static char p[] = "Hello, world"; long t = 7654321L; myprintf( "%%abc%Y\n"); myprintf( "%s\n", "abs" ); myprintf( "%5s|\n", "abs" ); myprintf( "%-5s|\n", "abs" ); myprintf( "%5s|\n", "xyzXYZ" ); myprintf( "%-5s|\n", "xyzXYZ" ); myprintf( "%5.5s|\n", "xyzXYZ" ); myprintf( "%-5.5s|\n", "xyzXYZ" ); myprintf( "%r\n", 444 ); myprintf( "%r\n", 999 ); myprintf( "%r\n", 16 ); myprintf( "%r\n", 18 ); myprintf( "%r\n", 479 ); myprintf( "%d\n", 1234 ); myprintf( "%d\n", -1234 ); myprintf( "%ld\n", 97487483 ); myprintf( "%2d|%2d|\n", 1, -3 ); myprintf( "%-2d|%-2d|\n", 1, -3 ); myprintf( "%02d|%2d|\n", 1, -3 ); myprintf( "%-02d|%-2d|\n", 1, -3 ); myprintf( "%5d|\n", -12 ); myprintf( "%05d|\n", -12 ); myprintf( "%-5d|\n", -12 ); myprintf( "%-05d|\n", -12 ); for( i = -6; i < 6; i++ ) myprintf( "width=%2d|%0*d|%0*d|%*d|%*d|\n", i, i, 123, i, -123, i, 123, i, -123); myprintf( "%s at location %a\n", s, s ); myprintf( "%ld\n", t ); n = 1; t = 1L; for( i=0; i < 34; i++ ){ myprintf( "for %2d |%016b|%d|%u|\n\t |%032lb|%ld|%lu|\n", i, n, n, n, t, t, t ); n *= 2; t *= 2; } myprintf( "%8x %8X\n", 7777, 7777 ); myprintf( "|%s|\n", p ); myprintf( "|%10s|\n", p ); myprintf( "|%-10s|\n", p ); myprintf( "|%20s|\n", p ); myprintf( "|%-20s|\n", p ); myprintf( "|%20.10s|\n", p ); myprintf( "|%-20.10s|\n", p ); myprintf( "|%.10s|\n", p ); }




- Начало -  - Назад -  - Вперед -



Книжный магазин