Person struct IO

Solution index                   Textual C program


/* Library for input/output of person records.
   Programmed by Kurt Normark, April 2003 */

#include <stdio.h>
#include "person-read-write.h"

/* Allocated memory to a person, and allocate strings to be initialized by the 
   string constants passed as parameter */
person *make_person(const char *name, const int age, const char sex){
  static person *result;
  result = (person*)malloc(sizeof(person));

  /* Copy string constants to dynamically allocated strings */
  result->name = strcpy((char *)calloc(strlen(name)+1,sizeof(char)), 
			name);
  result->age = age;
  result->sex = sex;
 
  return result;
}

/* pretty print person p to standard output */
void prnt_person(person *p){
  printf("Name: %s\n"
         "Age: %i\n"
         "Sec: %c\n",
         p->name, p->age, p->sex);
}

char *white_space_protect(char *str){
  int str_lgt = strlen(str), i, j;
  for(i = 0; i < str_lgt; i++){
    if (str[i] == ' ')
      str[i] = PROTECTED_SPACE;
    else if (str[i] == '\n')
      str[i] = PROTECTED_NEWLINE;
  } 
  return str;
} 

char *white_space_deprotect(char *str){
  int str_lgt = strlen(str), i;
  for(i = 0; i < str_lgt; i++){
    if (str[i] == PROTECTED_SPACE)
      str[i] =  ' ';
    else if (str[i] == PROTECTED_NEWLINE)
      str[i] = '\n';
  }
  return str;
} 

/* Encode the person pointed to by p in the string str */
void encode_person(person *p, char *str){
  sprintf(str, "%s %i %c\n", 
          white_space_protect(p->name),
          p->age, p->sex);
} 

/* Decode the string str to a person and return it */
person *decode_person(char *str){
  char name[100];
  int age;
  char sex;

  sscanf(str, "%s %i %c", 
         name, &age, &sex);
    
  return make_person(white_space_deprotect(name), 
                     age, sex);
}


void print_person(person *p, FILE *ofp){
  char buffer[BUFFER_MAX];
  encode_person(p, buffer);
  fprintf(ofp, "%s", buffer);
}

person *read_person(FILE *ifp){
  char buffer[BUFFER_MAX];
  fgets(buffer, BUFFER_MAX, ifp);
  return decode_person(buffer);
}


We program a library with input output functions for a person struct. The pattern of the solution given here can be used on many other structs. In addition to the c file dissected below, you must write a header file and c programs that write and read structs. For more details about these you can consult Kurt Nørmark's C slides on IO.
 

/* Allocated memory to a person, and allocate strings to be initialized by the 
   string constants passed as parameter */
person *make_person(const char *name, const int age, const char sex){
  static person *result;
  result = (person*)malloc(sizeof(person));

  /* Copy string constants to dynamically allocated strings */
  result->name = strcpy((char *)calloc(strlen(name)+1,sizeof(char)), 
			name);
  result->age = age;
  result->sex = sex;
 
  return result;
}
The function make-person creates a person struc and returns a pointer to it. The main aspects to notice in this function is the memory allocation of a person struct, and the allocation of memory to the strings. We need to modify the string constituents of the struct, and therefore the string constants, passed as parameter, must be copied to a location in memory that allows us to modify the strings.
 

/* pretty print person p to standard output */
void prnt_person(person *p){
  printf("Name: %s\n"
         "Age: %i\n"
         "Sec: %c\n",
         p->name, p->age, p->sex);
}
The function prnt_person is very simple. It just pretty prints the person data on standard output. It is not really important for our primary job of this library.
 

char *white_space_protect(char *str){
  int str_lgt = strlen(str), i, j;
  for(i = 0; i < str_lgt; i++){
    if (str[i] == ' ')
      str[i] = PROTECTED_SPACE;
    else if (str[i] == '\n')
      str[i] = PROTECTED_NEWLINE;
  } 
  return str;
} 
This function is used to protect white space characters in a string. We go for a solution in which a struct is printed on a single line, and a solution that allows us to read a string with scanf using the %s conversion character. Recall, that scanf stops on space or newline. Therefore, these characters will have be transformed before the struct is written. We transform spaces to PROTECTED_SPACE (which happens to be '@') and newline to PROTECTED_NEWLINE (which happens to be '$'). Both character constants are defined in person-read-write.h. As an important observation, these two characters can not be used as ordinary characters in the string valued fields.
 

char *white_space_deprotect(char *str){
  int str_lgt = strlen(str), i;
  for(i = 0; i < str_lgt; i++){
    if (str[i] == PROTECTED_SPACE)
      str[i] =  ' ';
    else if (str[i] == PROTECTED_NEWLINE)
      str[i] = '\n';
  }
  return str;
} 
The function white-space-deprotect does the inverse transformation of white_space_protect.
 

/* Encode the person pointed to by p in the string str */
void encode_person(person *p, char *str){
  sprintf(str, "%s %i %c\n", 
          white_space_protect(p->name),
          p->age, p->sex);
} 
The encode_person function prints the encoding of the person *p to the string str, which is passed by reference to this function. The encoding is done - conveniently - by sprintf, which prints into a string.
 

/* Decode the string str to a person and return it */
person *decode_person(char *str){
  char name[100];
  int age;
  char sex;

  sscanf(str, "%s %i %c", 
         name, &age, &sex);
    
  return make_person(white_space_deprotect(name), 
                     age, sex);
}
The function decode_person is the opposite function of encode_person. It scans the string str, which is passed as parameter in order to extract the encoded person fields. When this is done, it creates a person by use of the earlier programmed make_person function. Notice the use of white_space_deprotect.
 

void print_person(person *p, FILE *ofp){
  char buffer[BUFFER_MAX];
  encode_person(p, buffer);
  fprintf(ofp, "%s", buffer);
}
print_person is a top level function of the library. It allocates a string buffer, in which encode_person encodes the person p. Finally, the encoded person is written to the output file ofp.
 

person *read_person(FILE *ifp){
  char buffer[BUFFER_MAX];
  fgets(buffer, BUFFER_MAX, ifp);
  return decode_person(buffer);
}
The function read_person retrieves a person from the input file ifp. It first reads a single line of text from ifp. It then decodes the string using the function decode_person, and the resulting person struct pointer is returned from read_person.
 

A final word on compilation, for those who do it manually (without use of make). The library can be compiled by:
  gcc -c person-read-write.c
The two programs using the library can be compiled with
  gcc person-write-prog.c person-read-write.o -o person-write-prog
and
  gcc person-read-prog.c person-read-write.o -o person-read-prog
 


Generated: Wednesday, March 29, 2006, 12:33:15
This program dissection page is generated from an XML-in-LAML source file