Chapter 7: Input/Output.

Original C examples from the existing C programming archive. Source text is preserved; these historical examples have not been compiled or tested against a current toolchain.

test3.c

Despite its .c filename, this archive entry contains plain sample text rather than a C program. It is retained as the output-side fixture used by the line-copy example. The words have no C execution semantics and should not be compiled as source.

hello world
line test new prog
stdlib test file
bye

cat.c

This basic concatenator opens each named file, copies its characters to standard output and closes it; with no filenames it copies standard input instead. It introduces FILE pointers and stream operations. The simple error message goes to standard output, and the variant does not comprehensively report read/write failures.

#include<stdio.h>

int main(int argc, char *argv[])
{
  FILE *fp;
  void filecopy(FILE *, FILE *);

  if (argc==1) filecopy(stdin, stdout);
  else
     while (--argc > 0)
       if ((fp=fopen(*++argv, "r")) == NULL)
         {
           printf("cat: can't open %s\n", *argv);
           return 1;
         }
       else
        {
          filecopy(fp, stdout);
          fclose(fp);
        }

   return 0;
  
}


void filecopy(FILE *ifp, FILE *ofp)
 {
   int c;
 
   while ((c=getc(ifp)) != EOF)
     putc(c, ofp);
 }

cat2.c

This concatenation variant reports diagnostics to standard error, includes the invoked program name and checks for an output-stream error. That separates data from failure messages and distinguishes exit outcomes. The preserved code calls exit without including its declaring standard header, a modern-build defect to review.

#include<stdio.h>

int main(int argc, char *argv[])
{
  FILE *fp;
  void filecopy(FILE *, FILE *);
  char *prog = argv[0];

  if (argc==1) filecopy(stdin, stdout);
  else
     while (--argc > 0)
       if ((fp=fopen(*++argv, "r")) == NULL)
         {
           fprintf(stderr, "%s: can't open %s\n", prog, *argv);
           exit(1);
         }
       else
        {
          filecopy(fp, stdout);
          fclose(fp);
        }

  if (ferror(stdout))
    {
       fprintf(stderr, "%s: error writing stdout\n", prog);
       exit(2);
    }
  
   exit(0);
  
}


void filecopy(FILE *ifp, FILE *ofp)
 {
   int c;
 
   while ((c=getc(ifp)) != EOF)
     putc(c, ofp);
 }

lio.c

This line-I/O exercise implements small fgets-like and fputs-like helpers, copies the fixed test2.c input into test3.c and then reads standard input to report line lengths. Opening test3.c for writing can truncate an existing file. Missing open-failure checks mean it must not be treated as a safe general file copier.

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

#define SIZE 1000

char *fgets1(char *s, int n, FILE *iop);
int fputs1(char *s, FILE *iop);
int getline(char *line, int max);
char line[SIZE];

int main(int argc, char *argv[])
{
 FILE *iop,*iop2;
 int n=0;
 iop = fopen("test2.c", "r");
 iop2 = fopen("test3.c","w");
 while(fgets1(line,SIZE,iop))
  { 
    printf("%s",line);
    fputs1(line, iop2);
  }
fclose(iop);
fclose(iop2);

 while((n=getline(line,SIZE))>0)
  printf("Length:%d\n",n);

return 0;
}

char *fgets1(char *s, int n, FILE *iop)
 {
   register int c;
   register char *cs;

   cs = s;
   while (--n > 0 && (c=getc(iop)) != EOF)
    if ((*cs++ = c) == '\n')
      break;
    *cs = '\0';
   return (c==EOF && cs==s) ? NULL : s;
 }

int fputs1(char *s, FILE *iop)
 {
   int c;
  
   while (c = *s++)
    putc(c, iop);
   return ferror(iop) ? EOF : 0;
 }

int getline(char *line, int max)
 {
    if (fgets1(line, max, stdin) == NULL)
     return 0;
    else
     return strlen(line);
 }

minprintf.c

This miniature formatting function walks a format string and retrieves variadic arguments for integer, floating-point and string placeholders using va_list. The float argument is retrieved as double because default argument promotion applies. It omits most printf features and depends on the caller matching every placeholder to the correct argument type.

#include<stdio.h>
#include<stdarg.h>

void minprintf(char *fmt, ...);

int main()
{

 char *s = "Hello world\n";
 int iv = 32;
 float ifv = 25.260;
 minprintf("%s",s);
 minprintf("%d\n",iv);
 minprintf("%f\n",ifv);
 return 0;

}

void minprintf(char *fmt, ...)
{
  va_list ap;
  char *p, *sval;
  int ival;
  double dval;

  va_start(ap, fmt);

  for (p=fmt; *p; p++)
  {
    if (*p != '%')
     {
       putchar(*p);
       continue;
     }

    switch(*++p)
      {
         case 'd':
                ival = va_arg(ap, int);
                printf("%d", ival);
                break;
         case 'f':
                dval = va_arg(ap, double);
                printf("%f", dval);
                break;
	case 's':
                for (sval = va_arg(ap, char*); *sval; sval++)
                 putchar(*sval);
                break;
        default:
                putchar(*p);
                break;
        }
    }
 va_end(ap);
}

sscanf.c

This parser tries a textual month form and then a slash-separated numeric date, using the assignment count to recognize a matching input shape. Matching three fields does not prove a valid calendar date. The unbounded string conversion can overflow monthname, and the custom reader has the pointer-termination defect noted in other archive examples.

#include<stdio.h>
#define SIZE 50 

int getline(char *s, int lim);

int main()
{
int day, month, year;
char monthname[20];
char line[SIZE];
  
 while (getline(line, sizeof(line)) > 0)
  {
    if (sscanf(line, "%d %s %d", &day, monthname, &year) ==3)
      printf("valid: %s\n", line);
    else if (sscanf(line, "%d/%d/%d", &month, &day, &year) ==3)
      printf("valid: %s\n", line);
    else
      printf("invalid: %s\n", line);
  }

return 0;
}

int getline(char *s, int lim)
{
  int c, i;
  i=0;
  while(--lim > 0 && (c=getchar()) != EOF && c!='\n')
    { *s++=c; i++; }
  if(c=='\n')
   { *s++=c; i++; }
  s[i]='\0';
 return i;
}

sum.c

This example intends to add a variable number of integer arguments until a sentinel value of minus one. Variadic arguments must be consumed with va_arg; the preserved loop instead inspects va_list internals through dereferencing, which is not portable and can fail to compile. It is an incomplete demonstration of sentinel-based iteration.

#include<stdio.h>
#include<stdarg.h>

int total(int one, ...);

int main()
{

 printf("Total=%d\n",total(10,20,30,40,15,-1));
 return 0;

}

int total(int one, ...)
{
  int sum=0;
  va_list ap;
  va_start (ap, one);
  sum=one;
  while (*ap!=-1)
   sum+=(va_arg(ap,int));
  va_end(ap);
return sum;
}

test2.c

This .c-named entry is plain text used as the input fixture for lio.c. Keeping it in the chapter explains the otherwise surprising hard-coded filename in the line-copy example. It contains sample records, not declarations or executable C statements.

hello world
line test new prog
stdlib test file
bye

calc.c

This running-total program repeatedly asks scanf to convert one double and prints the updated sum after each successful conversion. Comparing the return value with one stops on EOF or an unconvertible token. It is a compact formatted-input exercise, without a recovery strategy for malformed records.

#include<stdio.h>

int main()
{
  double sum, v;
  sum = 0;
 
  while (scanf("%lf", &v) == 1)
     printf("\t %.2f\n", sum+=v);
  return 0;
}