Difference between revisions of "2016-17 Programmi C"
		
		
		
		
		
		Jump to navigation
		Jump to search
		
				
		
		
	
| m | |||
| Line 322: | Line 322: | ||
| This technique is used to implement callbacks with opaque args. | This technique is used to implement callbacks with opaque args. | ||
| + | |||
| + | = Programs using libraries = | ||
| + | |||
| + | == char by char copy (stdio) == | ||
| + | <syntaxhighlight lang=C> | ||
| + | #include <stdio.h> | ||
| + | |||
| + | int main(int argc, char *argv[]) { | ||
| + |   int c; | ||
| + |   while ((c = getchar()) != EOF) | ||
| + |     putchar(c); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | == similar programs, different approaches (stdio, string, stdlib, ctype) | ||
| + | |||
| + | First program: | ||
| + | <syntaxhighlight lang=C> | ||
| + | #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; | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | Second program: | ||
| + | <syntaxhighlight lang=C> | ||
| + | #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; | ||
| + | } | ||
| + | </syntaxhighlight> | ||
Revision as of 14:32, 4 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;
  for (; *s != 0; s++) {
    if (*s == ' ' || *s == '\t' || *s == '\n') {
      if (state != SPACE)
        count++;
      if (argv != NULL)
        *s = 0;
      state = SPACE;
    } else {
      if (state == SPACE && argv != NULL)
        *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"
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;
}