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

Назад | Содержание | Вперед