Хрестоматия по программированию на Си в Unix
обращение по записи в эту страницу вызывает прерывание от диспетчера памяти и аварий-
ное прекращение процесса. Система сама помогает ловить ваши ошибки (но уже во время
выполнения программы). Это ОЧЕНЬ частая ошибка - запись по адресу NULL. MS DOS в
таких случаях предпочитает просто зависнуть, и вы бываете вынуждены играть аккорд из
трех клавиш - Ctrl/Alt/Del, так и не поняв в чем дело.
2.60. Раз уж речь зашла о функции 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'.
2.61. Упрощенный аналог функции printf.
А. Богатырев, 1992-95 - 113 - Си в UNIX
/*
* Машинно - независимый printf() (упрощенный вариант).
* printf - Форматный Вывод.
*/
#include
#include
#include
#include
#include
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++;
}
А. Богатырев, 1992-95 - 114 - Си в UNIX
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);
}
А. Богатырев, 1992-95 - 115 - Си в UNIX
/* --------------------------------------------------------- */
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);
}
А. Богатырев, 1992-95 - 116 - Си в UNIX
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 );
}
А. Богатырев, 1992-95 - 117 - Си в UNIX
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); }
}
}
А. Богатырев, 1992-95 - 118 - Си в UNIX
/* --------------------------------------------------------- */
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 );