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.
/*
* Машинно - независимый 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 );
}
Выдача этой программы:
%abcY
abs
abs|
abs |
xyzXYZ|
xyzXYZ|
xyzXY|
xyzXY|
CDXLIV
CMXCIX
XVI
XVIII
CDLXXIX
1234
-1234
97487483
1|-3|
1 |-3|
01|-3|
1 |-3|
-12|
-0012|
-12 |
-12 |
width=-6|123 |-123 |123 |-123 |
width=-5|123 |-123 |123 |-123 |
width=-4|123 |-123|123 |-123|
width=-3|123|-123|123|-123|
width=-2|123|-123|123|-123|
width=-1|123|-123|123|-123|
width= 0|123|-123|123|-123|
width= 1|123|-123|123|-123|
width= 2|123|-123|123|-123|
width= 3|123|-123|123|-123|
width= 4|0123|-123| 123|-123|
width= 5|00123|-0123| 123| -123|
Hello, world!
at location 400980
7654321
for 0 |0000000000000001|1|1|
|00000000000000000000000000000001|1|1|
for 1 |0000000000000010|2|2|
|00000000000000000000000000000010|2|2|
for 2 |0000000000000100|4|4|
|00000000000000000000000000000100|4|4|
for 3 |0000000000001000|8|8|
|00000000000000000000000000001000|8|8|
for 4 |0000000000010000|16|16|
|00000000000000000000000000010000|16|16|
for 5 |0000000000100000|32|32|
|00000000000000000000000000100000|32|32|
for 6 |0000000001000000|64|64|
|00000000000000000000000001000000|64|64|
for 7 |0000000010000000|128|128|
|00000000000000000000000010000000|128|128|
for 8 |0000000100000000|256|256|
|00000000000000000000000100000000|256|256|
for 9 |0000001000000000|512|512|
|00000000000000000000001000000000|512|512|
for 10 |0000010000000000|1024|1024|
|00000000000000000000010000000000|1024|1024|
for 11 |0000100000000000|2048|2048|
|00000000000000000000100000000000|2048|2048|
for 12 |0001000000000000|4096|4096|
|00000000000000000001000000000000|4096|4096|
for 13 |0010000000000000|8192|8192|
|00000000000000000010000000000000|8192|8192|
for 14 |0100000000000000|16384|16384|
|00000000000000000100000000000000|16384|16384|
for 15 |1000000000000000|32768|32768|
|00000000000000001000000000000000|32768|32768|
for 16 |10000000000000000|65536|65536|
|00000000000000010000000000000000|65536|65536|
for 17 |100000000000000000|131072|131072|
|00000000000000100000000000000000|131072|131072|
for 18 |1000000000000000000|262144|262144|
|00000000000001000000000000000000|262144|262144|
for 19 |10000000000000000000|524288|524288|
|00000000000010000000000000000000|524288|524288|
for 20 |100000000000000000000|1048576|1048576|
|00000000000100000000000000000000|1048576|1048576|
for 21 |1000000000000000000000|2097152|2097152|
|00000000001000000000000000000000|2097152|2097152|
for 22 |10000000000000000000000|4194304|4194304|
|00000000010000000000000000000000|4194304|4194304|
for 23 |100000000000000000000000|8388608|8388608|
|00000000100000000000000000000000|8388608|8388608|
for 24 |1000000000000000000000000|16777216|16777216|
|00000001000000000000000000000000|16777216|16777216|
for 25 |10000000000000000000000000|33554432|33554432|
|00000010000000000000000000000000|33554432|33554432|
for 26 |100000000000000000000000000|67108864|67108864|
|00000100000000000000000000000000|67108864|67108864|
for 27 |1000000000000000000000000000|134217728|134217728|
|00001000000000000000000000000000|134217728|134217728|
for 28 |10000000000000000000000000000|268435456|268435456|
|00010000000000000000000000000000|268435456|268435456|
for 29 |100000000000000000000000000000|536870912|536870912|
|00100000000000000000000000000000|536870912|536870912|
for 30 |1000000000000000000000000000000|1073741824|1073741824|
|01000000000000000000000000000000|1073741824|1073741824|
for 31 |10000000000000000000000000000000|-2147483648|2147483648|
|10000000000000000000000000000000|-2147483648|2147483648|
for 32 |0000000000000000|0|0|
|00000000000000000000000000000000|0|0|
for 33 |0000000000000000|0|0|
|00000000000000000000000000000000|0|0|
1e61 1E61
|Hello, world|
|Hello, world|
|Hello, world|
| Hello, world|
|Hello, world |
| Hello, wor|
|Hello, wor |
|Hello, wor|
2.62.
Рассмотрим программу суммирования векторов:
int A[1024], B[1024], C[1024];
...
for(i=0; i < 1024; i++) C[i] = A[i] + B[i];
А почему бы не
for(i=1024-1; i >=0 ; --i) ...;
А почему бы не в произвольном порядке?
foreach i in (0..1023) ...;
Данный пример показывает, что некоторые операции обладают врожденным паралеллизмом, ведь все 1024 сложений можно было бы выполнять параллельно! Однако тупой компилятор
будет складывать их именно в том порядке, в котором вы ему велели. Только самые современные компиляторы на многопроцессорных системах умеют автоматически распараллеливать такие циклы. Сам язык Си не содержит средств указания параллельности (разве что
снова - библиотеки и системные вызовы для этого).
© Copyright А. Богатырев, 1992-95
Си в UNIX
Назад | Содержание | Вперед