Difference between revisions of "2016-17 Programmi C"

From Sistemi Operativi
Jump to navigation Jump to search
Line 742: Line 742:
 
char *strcpy4(char *dest, const char *src) {
 
char *strcpy4(char *dest, const char *src) {
 
   if ((*dest = *src) != 0)
 
   if ((*dest = *src) != 0)
     strcpy3(dest+1, src+1);
+
     strcpy4(dest+1, src+1);
 
   return dest;
 
   return dest;
 
}
 
}

Revision as of 08:32, 15 October 2016

C language - No Libraries

The following programs do not use library functions (only printf, just to have a feedback of the results).

arrays, pointers and structs

#include <stdio.h>

char *spoint="hello";
char sarr[]="hello";
struct strs {
  char s[6];
} sstruct = {"hello"};

void foo(char *s) {
  s[4]=0;
}

void bar(struct strs s) {
  s.s[4]=0;
  printf("from bar %s\n", s.s);
}

int main(int argc, char *argv[]) {
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
  foo(sarr);
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
  bar(sstruct);
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
  // test the following statements, one at a time
  //spoint = sarr;
  //sarr = spoint;
  foo(spoint);
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
}

iteration and recursion

#include <stdio.h>

struct elem {
  int val;
  struct elem *next;
};

struct elem *head = NULL;

struct elem *rinsert(struct elem *new, struct elem *head) {
  if (head == NULL || new->val < head->val) {
    new->next = head;
    return new;
  } else {
    head->next = rinsert(new, head->next);
    return head;
  }
}

struct elem *iinsert(struct elem *new, struct elem *head) {
  struct elem **pnext;
  for (pnext = &head;
      *pnext != NULL && new->val > (*pnext)->val;
      pnext = &((*pnext)->next))
    ;
  new->next = *pnext;
  *pnext = new;
  return head;
}

void rprint(struct elem *this) {
  if (this) {
    printf("%d ",this->val);
    rprint(this->next);
  }
}

void iprint(struct elem *this) {
  for ( ; this != NULL; this = this->next)
    printf("%d ",this->val);
}

struct elem test[]={{5},{3},{9},{1},{7}};
#define NELEM (sizeof(test) / sizeof(struct elem))

int main(int argc, char *argv[]) {
  int i;
  for (i = 0; i < NELEM; i++)
    head = rinsert(&test[i], head);
  rprint(head);
  printf("\n");
  iprint(head);
  printf("\n");
  head = NULL;
  for (i = 0; i < NELEM; i++)
    head = iinsert(&test[i], head);
  rprint(head);
  printf("\n");
  iprint(head);
  printf("\n");
}

comma operator

#include <stdio.h>

int slen(char *s) { /* in real programs use strlen instead */
  size_t rval;
  for (rval = 0; *s != 0; s++, rval++)
    ;
  return rval;
}

int ispal(char *s) {
  int i,j;
  for (i=0, j=slen(s)-1; i < j; i++, j--) {
    if (s[i] != s[j])
      return 0;
  }
  return 1;
}

void reverse(char *s) {
  int i,j;
  for (i=0, j=slen(s)-1; i < j; i++, j--)
    s[j] ^= s[i] ^= s[j] ^= s[i];
}

int main(int argc, char *argv[1]) {
  for ( ;argc > 1; argv++, argc--) {
    printf("\"%s\" is%s palindrome\n", argv[1],
        ispal(argv[1])?"":"n't");
    reverse(argv[1]);
    printf("\"%s\"\n", argv[1]);
  }
}

string by value

#include <stdio.h>

int slen(char *s) { /* in real programs use strlen instead */
  int rval;
  for (rval = 0; *s != 0; s++, rval++)
    ;
  return rval;
}

void printxvowel(char v, char *s) {
  int s_len = slen(s);
  char locals[s_len];
  int i;
  for (i=0; i<s_len; i++) {
    switch (s[i]) {
      case 'a':
      case 'e':
      case 'i':
      case 'o':
      case 'u':
        locals[i] = v;
        break;
      default:
        locals[i] = s[i];
        break;
    }
  }
  printf("-> %s\n<- %s\n",s,locals);
}

int main(int argc, char *argv[]) {
  for ( ; argc > 1; argc--, argv++) {
    printxvowel('a',argv[1]);
    printxvowel('e',argv[1]);
    printxvowel('i',argv[1]);
    printxvowel('o',argv[1]);
    printxvowel('u',argv[1]);
  }
  return 0;
}

test it using "Garibaldi fu ferito, fu ferito ad una gamba, Garibaldi che comanda, che comanda il battaglion" as argv[1].

tables and preprocessor tricks

#include <stdio.h>

#define rows_of(X) (sizeof(X) / sizeof((X)[0]))

#define printTable(X) do { \
    int i; \
    printf("TABLE " #X ": size of element %d\n" \
        "(printed by the line %d of source file %s)\n",  \
        sizeof(*(table ## X)), __LINE__, __FILE__); \
    for (i = 0; i < rows_of(table ## X); i++)  \
      printf(#X " %02d %s\n",i,table ## X [i]); \
    } while (0);

char tableA[][50] = {"Sempre caro mi fu quest'ermo colle,",
  "e questa siepe, che da tanta parte",
  "dell’ultimo orizzonte il guardo esclude."};
char *tableB[] = {"Sempre caro mi fu quest'ermo colle,",
  "e questa siepe, che da tanta parte",
  "dell’ultimo orizzonte il guardo esclude."};

int main(int argc, char *argv[1]) {
  int i;
  printTable(A);
  printf("\n");
  printTable(B);
}

arrays and pointers

#include <stdio.h>

int slen(char *s) { /* in real programs use strlen instead */
  size_t rval;
  for (rval = 0; *s != 0; s++, rval++)
    ;
  return rval;
}

void echoargs(int argc, char *argv[]) {
  int i;
  for (i = 0; i < argc; i++)
    printf("argv[%d] = \"%s\"\n",i,argv[i]);
  printf("\n");
}

enum state {SPACE, CHAR};

int splitargv(char *s, char **argv) {
  enum state state = SPACE;
  int count = 0;
  //until the string is finished
  for (; *s != 0; s++) {
    //if s point to a character that is a space or a tab or a new line
    if (*s == ' ' || *s == '\t' || *s == '\n') {
      if (state != SPACE)
        count++;
      if (argv != NULL)
        //insert a zero for ending the string
        *s = 0;
      state = SPACE;
    } else {
      if (state == SPACE && argv != NULL)
        //if it is in SPACE state but the pointed character is not a "space" it splits the string by setting that the next element of the argv array should point to the new string.
        *argv++ = s;
      state = CHAR;
    }
  };
  if (state != SPACE)
    count++;
  if (argv != NULL)
    *argv = NULL;
  return count;
}

void splitargs(char *args) {
  int newargc = splitargv(args, NULL);
  char *newargv[newargc + 1];
  splitargv(args, newargv);
  echoargs(newargc, newargv);
}

int main(int argc, char *argv[1]) {
  echoargs(argc, argv);
  for ( ; *argv != NULL; argv++) {
    printf("Split \"%s\"\n",*argv);
    splitargs(*argv);
  }
}

This is a simplified version of the idea used in the libexecs library. Test this program using args like:

./a.out "ciao               mare" "a      b c"

This program split the strings contained in the argv array by truncating them on space, tab and new line characters.
The new strings are inserted in the argv array and argc is increased properly. FedericoB (talk)

void * and function pointers

#include <stdio.h>

typedef void (*voidfun) (void *arg);

void printint(void *arg) {
  int *iarg = arg;
  printf("int %d\n", *iarg);
}

void printstring(void *arg) {
  char *sarg = arg;
  printf("int %s\n", sarg);
}

void printpointer(void *arg) {
  printf("pointer %p\n", arg);
}

void printfun(void *arg) {
  voidfun fun = arg;
  fun((void *) 0x42);
}

void launch(voidfun f, void *opaque) {
  f(opaque);
}

int main(int argc, char *argv[1]) {
  int v = 235;
  char *s = "Lasciate ogni speranza, o voi ch'entrate";
  launch(printint, &v);
  launch(printstring, s);
  launch(printfun, printpointer);
  return 0;
}

This technique is used to implement callbacks with opaque args.

Programs using libraries

char by char copy (stdio)

#include <stdio.h>

int main(int argc, char *argv[]) {
  int c;
  while ((c = getchar()) != EOF)
    putchar(c);
}

similar programs, different approaches (stdio, string, stdlib, ctype)

First program:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define BUFLEN 4096

char *loadfile(char *path) {
  char *contents = NULL;
  size_t contents_len = 0;
  char buffer[BUFLEN];
  size_t len;
  FILE *fin = fopen(path, "r");
  FILE *fout = open_memstream(&contents, &contents_len);
  if (fin == NULL || fout == NULL)
    exit(1);
  while ((len = fread(buffer, sizeof(char), BUFLEN, fin)) > 0)
    fwrite(buffer, sizeof(char), len, fout);
  fclose(fin);
  fclose(fout);
  return(contents);
}

enum state {SPACE, CHAR};

int splitwords(char *s, char **words) {
  enum state state = SPACE;
  int count = 0;
  for (; *s != 0; s++) {
    if (isalnum(*s)) {
      if (state == SPACE && words != NULL)
        *words++ = s;
      state = CHAR;
    } else {
      if (state != SPACE)
        count++;
      if (words != NULL)
        *s = 0;
      state = SPACE;
    }
  };
  if (state != SPACE)
    count++;
  return count;
}

static int sortcmp(const void *p1, const void *p2) {
  const char *s1 = *(char * const *) p1;
  const char *s2 = *(char * const *) p2;
  int rval = strlen(s1) - strlen(s2);
  if (rval == 0)
    rval = strcmp(s1, s2);
  return rval;
}

int main(int argc, char *argv[1]) {
  if (argc == 2) {
    char *contents = loadfile(argv[1]);
    int count = splitwords(contents, NULL);
    char **words = malloc(count * sizeof(char *));
    if (words == NULL)
      return 1;
    else {
      int i;
      splitwords(contents, words);
      qsort(words, count, sizeof(char *), sortcmp);
      for (i = 0; i < count; i++)
        printf("%s\n", words[i]);
      return 0;
    }
  } else
    return 1;
}

Second program:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

struct word {
  struct word *next;
  int count;
  char word[];
};

static int lenalphacmp(const char *s1, const char *s2) {
  int rval = strlen(s1) - strlen(s2);
  if (rval == 0)
    rval = strcmp(s1, s2);
  return rval;
}

struct word *addword(char *word, struct word *wlist) {
  struct word **scan;
  int cmpvalue;
  for (scan = &wlist;
      *scan != NULL && ((cmpvalue = lenalphacmp(word, (*scan)->word)) > 0);
      scan = &((*scan)->next))
    ;
  if (scan != NULL && cmpvalue == 0)
    (*scan)->count ++;
  else {
    struct word *new = malloc(sizeof(struct word) + strlen(word) + 1);
    if (new) {
      new->next = *scan;
      new->count = 1;
      strcpy(new->word, word);
      *scan = new;
    }
  }
  return wlist;
}

struct word *addwordlen(char *word, size_t len,  struct word *wlist) {
  char word0[len+1];
  strncpy(word0,word,len);
  word0[len]=0;
  return addword(word0, wlist);
}

struct word *processline(char *line, struct word *wlist) {
  char *thisword = NULL;
  for ( ;*line != 0; line++) {
    if (isalnum(*line)) {
      if (thisword == NULL)
        thisword = line;
    } else {
      if (thisword != NULL) {
        wlist = addwordlen(thisword, line - thisword, wlist);
        thisword = NULL;
      }
    }
  }
  return wlist;
}

void printwlist(struct word *wlist) {
  for ( ; wlist != NULL; wlist = wlist->next)
    printf("%s : %d\n", wlist->word, wlist->count);
}

int main(int argc, char *argv[1]) {
  if (argc == 2) {
    FILE *fin = fopen(argv[1], "r");
    ssize_t len;
    char *linebuf = NULL;
    size_t linebuflen = 0;
    struct word *wlist = NULL;
    while ((len = getline(&linebuf, &linebuflen, fin)) > 0)
      wlist = processline(linebuf, wlist);
    fclose(fin);
    free(linebuf);
    printwlist(wlist);
    return 0;
  } else
    return 1;
}

Command line args management (getopt)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <libgen.h>

void usage_and_exit(char *progname) {
  fprintf(stderr,
      "Usage:\n"
      "  %s OPTIONS [value] ... [value]\n"
      "Options:\n"
      "  -v | --verbose:      verbose mode\n"
      "  -h | --help:         print a short usage helping message\n"
      "  -a val | --add val   add a value\n"
      "  -s val | --sub val   subtract a value\n"
      "  --double             double the final result\n"
      "This program computes an integer value\n", progname);
  exit(1);
}

int main(int argc, char *argv[]) {
  static struct option long_options[] = {
    {"verbose", no_argument, 0, 'v'},
    {"help",    no_argument, 0, 'h'},
    {"add",     required_argument, 0, 'a'},
    {"sub",     required_argument, 0, 's'},
    {"double",  no_argument, 0, 0x101},
  };
  static char *short_options = "vha:s:";

  int opt;

  int value = 0;
  int verbose = 0;
  int doubleval = 1;

  char *progname = basename(argv[0]);

  while((opt = getopt_long(argc, argv, short_options, long_options, NULL)) > 0) {
    switch (opt) {
      case 'v': verbose = 1;
                break;
      case 'a': value += atoi(optarg);
                break;
      case 's': value -= atoi(optarg);
                break;
      case 0x101: doubleval *= 2;
                  break;
      case 'h':
      case '?': usage_and_exit(progname);
                break;
    }
  }
  for (; optind < argc; optind++)
    value += atoi(argv[optind]);

  value *= doubleval;

  if (verbose)
    printf("the result is %d\n", value);

  return value;
}

dynamic allocation on the heap, qsort, getline (stdlib)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define AOS_LENSTEP 8

struct array_of_strings {
  char **strings;
  size_t currentlen;
  size_t arraylen;
};

typedef struct array_of_strings array_of_strings;

void array_of_strings_add(array_of_strings *v, char *s) {
  if (v->currentlen >= v->arraylen) {
    size_t newlen = v->arraylen + AOS_LENSTEP;
    char **new_s = realloc(v->strings, newlen * sizeof(v->strings[0]));
    if (new_s != NULL) {
      v->arraylen = newlen;
      v->strings = new_s;
    }
  }
  if (v->currentlen < v->arraylen)
    v->strings[v->currentlen++] = strdup(s);
}

void array_of_strings_print(array_of_strings *v) {
  size_t i;
  for (i = 0; i < v->currentlen; i++)
    printf("[%3lu]: %s\n", i, v->strings[i]);
}

static int alphasort(const void *a, const void *b) {
  return strcmp(* (char **) a, * (char **) b);
}

void array_of_strings_sort(array_of_strings *v) {
  qsort(v->strings, v->currentlen, sizeof(v->strings[0]), alphasort);
}

void array_of_strings_free(array_of_strings *v) {
  size_t i;
  for (i = 0; i < v->currentlen; i++)
    free(v->strings[i]);
  if (v->arraylen > 0)
    free(v->strings);
}

int main(int argc, char *argv[]) {
  char *line = NULL;
  size_t linelen = 0;
  ssize_t nch;
  static array_of_strings aos;
  if (argc != 1)
    exit(1);

  while ((nch = getline(&line, &linelen, stdin)) >= 0) {
    if (line[nch - 1] == '\n')
      line[nch - 1] = 0;
    array_of_strings_add(&aos, line);
  }

  free(line);
  array_of_strings_sort(&aos);
  array_of_strings_print(&aos);
  array_of_strings_free(&aos);
}

open_memstream (quite tricky)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int alphasort(const void *a, const void *b) {
  return strcmp(* (char **) a, * (char **) b);
}

int main(int argc, char *argv[]) {
  char *line = NULL;
  size_t linelen = 0;
  ssize_t nch;
  FILE *fakefile;
  char *fakememfile = NULL;
  char **stringsarray;
  size_t stringsarraylen = 0;
  char **scan;
  char *dups;
  if (argc != 1)
    exit(1);

  fakefile = open_memstream(&fakememfile, &stringsarraylen);
  if (fakefile == NULL)
    exit(1);

  while ((nch = getline(&line, &linelen, stdin)) >= 0) {
    if (line[nch - 1] == '\n')
      line[nch - 1] = 0;
    if ((dups = strdup(line)) != NULL)
      fwrite(&dups, sizeof(dups), 1, fakefile);
  }

  free(line);
  dups = NULL;
  fwrite(&dups, sizeof(dups), 1, fakefile);
  fclose(fakefile);
  stringsarray = (char **) fakememfile;
  stringsarraylen /= sizeof(char *);
  stringsarraylen--;
  printf("%lu\n",stringsarraylen);
  qsort(stringsarray, stringsarraylen, sizeof(stringsarray[0]), alphasort);
  for (scan = stringsarray; *scan != NULL; scan++)
    printf("[%3lu]: %s\n", scan - stringsarray, *scan);
  for (scan = stringsarray; *scan != NULL; scan++)
    free(*scan);
  free(stringsarray);
}

fantasy of strcpy (time, stdint, string)

Cit. Cirano page 33.

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

char *strcpy0(char *dest, const char *src) {
  int i;
  int len;
  for (len = 0; src[len] != 0; len++)
    ;
  for (i = 0; i <= len; i++)
    dest[i] = src[i];
  return dest;
}

char *strcpy1(char *dest, const char *src) {
  int i;
  for (i = 0; src[i] != 0; i++)
    ;
  for ( ; i >= 0; i--)
    dest[i] = src[i];
  return dest;
}

char *strcpy2(char *dest, const char *src) {
  char *rval = dest;
  while ((*dest++ = *src++) != 0)
    ;
  return rval;
}

char *strcpy3(char *dest, const char *src) {
  int i;
  for (i=0; (dest[i] = src[i]) != 0; i++)
    ;
  return dest;
}

char *strcpy4(char *dest, const char *src) {
  if ((*dest = *src) != 0)
    strcpy4(dest+1, src+1);
  return dest;
}

char *strcpy5(char *dest, const char *src) {
  char *rval = dest;
  while (*src != 0)
    *dest++ = *src++;
  *dest = 0;
  return rval;
}


char *strcpy6(char *dest, const char *src) {
  uint64_t *src64 = (uint64_t *) src;
  uint64_t *dest64 = (uint64_t *) dest;
  while (1) {
    register uint64_t tmp = *src64;
    uint64_t scan;
    for (scan = 0xffULL; (tmp & scan) != 0; scan <<= 8)
      ;
    //printf("%llx %llx %p %p %s\n",scan, tmp, src64, dest64, (char *) src64);
    if (scan != 0) {
      strcpy2((char *) dest64, (char *) src64);
      break;
    }
    *dest64++ = tmp;
    src64++;
  }
  return dest;
}

#define NUMBER_OF_TEST 1000000

double time_strcpy(char * (*cpy)(char *, const char *), char *d, const char *s)
{
    clock_t starttime, time;
    int i;
    starttime = clock();
    for (i = 0; i< NUMBER_OF_TEST; i++)
    cpy(d, s);
    time = clock() - starttime;
    return (1.0) * time / CLOCKS_PER_SEC;
}

#define TESTSTRCPY(N,D,S) \
  printf("strcpy" #N " %s time %lf\n", strcpy ##N ((D),(S)), time_strcpy(strcpy ##N, (D),(S))) 

int main(int argc, char *argv[]) {
  if (argc != 2)
    return 1;
  else {
    size_t argv1len=strlen(argv[1]);
    char argcpy[argv1len+1];
    strncpy(argcpy, argv[1], argv1len);
    printf("strncpy %s\n", argcpy);
    TESTSTRCPY(, argcpy, argv[1]);
    TESTSTRCPY(0, argcpy, argv[1]);
    TESTSTRCPY(1, argcpy, argv[1]);
    TESTSTRCPY(2, argcpy, argv[1]);
    TESTSTRCPY(3, argcpy, argv[1]);
    TESTSTRCPY(4, argcpy, argv[1]);
    TESTSTRCPY(5, argcpy, argv[1]);
    TESTSTRCPY(6, argcpy, argv[1]);
  }
}

math and printf

#include <stdio.h>
#include <unistd.h>
#include <math.h>

#define DELAY 10000
#define DURATION 30

int main(int argc, char *argv[]) {
  double x;
  int i;
  for (i = 0; i < DURATION * 1000000 / DELAY; i++) {
    double y = sin(M_PI * i / 100);
    int pos = 40 + (40 * y);
    printf("\r%*s\b",pos,"*");
    fflush(stdout);
    usleep(DELAY);
    printf("\n");
  }
}

minishell (history and execs)

... questo esercizio richiede il caricamento di librerie da installare (history/readline da distribuzione, execs da github).

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <execs.h>

int main(int argc, char *argv[]) {
  while (1) {
    char *cmd = readline("% ");
    if (cmd == NULL)
      break;
    if (*cmd != 0) {
      add_history(cmd);
      system_nosh(cmd);
    }
    free(cmd);
  }
  printf("\n");
  return 0;
}

conversions (math)

#include <stdio.h>
#include <math.h>

int main() {
  char c;
  short s;
  int i;
  long l;
  long long ll;
  unsigned char uc;
  unsigned short us;
  unsigned int ui;
  unsigned long ul;
  unsigned long long ull;
  float f;
  double d;
  long double ld;

  c = s = i = l = ll = 0xc1c2c3c4c5c6c7c8;
  printf("%d %llx %lld\n", sizeof(ll), ll, ll);
  printf("%d %lx %ld\n", sizeof(l), l, l);
  printf("%d %x %d\n", sizeof(i), i, i);
  printf("%d %x %d\n", sizeof(s), s, s);
  printf("%d %x %d\n", sizeof(c), c, c);

  ll = l = i = s = c;
  printf("%d %x %d\n", sizeof(s), s, s);
  printf("%d %x %d\n", sizeof(i), i, i);
  printf("%d %lx %ld\n", sizeof(l), l, l);
  printf("%d %llx %lld\n", sizeof(ll), ll, ll);

  i = 1 << (sizeof(i) * 8 - 1);
  printf("%d %x %d\n", sizeof(i), i, i);
  i >>= 1;
  printf("%d %x %d\n", sizeof(i), i, i);
  i = -1;
  printf("%d %x %d\n", sizeof(i), i, i);
  i >>= 1;
  printf("%d %x %d\n", sizeof(i), i, i);

  uc = us = ui = ul = ull = 0xc1c2c3c4c5c6c7c8;
  printf("%d %llx %llu\n", sizeof(ull), ull, ull);
  printf("%d %lx %lu\n", sizeof(ul), ul, ul);
  printf("%d %x %u\n", sizeof(ui), ui, ui);
  printf("%d %x %u\n", sizeof(us), us, us);
  printf("%d %x %u\n", sizeof(uc), uc, uc);
  ull = ul = ui = us = uc;
  printf("%d %x %u\n", sizeof(us), us, us);
  printf("%d %x %u\n", sizeof(ui), ui, ui);
  printf("%d %lx %lu\n", sizeof(ul), ul, ul);
  printf("%d %llx %llu\n", sizeof(ull), ull, ull);

  f = d = ld = acosl(-1);
  printf("%2d %80.78llf\n", sizeof(ld), ld);
  printf("%2d %80.78lf\n", sizeof(d), d);
  printf("%2d %80.78f\n", sizeof(f), f);

  return 0;
}