New Topic: File Input and Output * Example Program: /* This program copies 10 numbers from "infile" to "outfile". We assume that "infile" already exists. */ #include int main(void) { 1 FILE *fp1; 2 FILE *fp2; 3 int i; 4 int value; 5 fp1 = fopen("infile", "r"); 6 fp2 = fopen("outfile", "w"); 7 for (i = 0; i < 10; i++) { 8 fscanf(fp1, "%d", &value); 9 printf("value %d: %d\n", i, value); 10 fprintf(fp2, "%d\n", value); 11 } 12 fclose(fp1); 13 fclose(fp2); 14 return(0); } Comments: * lines 1 and 2: you need to declare a "file pointer" for each file that you want to use. * line 5: fp1 = fopen("infile", "r"); * 1st argument is the name of the file * 2nd argument = what you want to do: "r" = read the file "w" = write to the file * line 8: use "fscanf" instead of scanf. 1st argument = the file pointer rest of arguments = same as for scanf * line 9: print each value to the screen * line 10: use "fprintf" instead of printf 1st argument = the file pointer rest of arguments = same as for printf * lines 12 and 13: use fclose to close each file * Assume infile exists already, and looks like this: 10 20 30 40 50 60 70 80 90 100 * Example 2 #include 1 int main(void) 2 { 3 FILE *fp1; 4 FILE *fp2; 5 char infile[25]; 6 char outfile[25]; 7 int c; 8 printf("Enter name of input file: "); 9 scanf("%s", infile); 10 printf("Enter name of output file: "); 11 scanf("%s", outfile); 12 fp1 = fopen(infile, "r"); 13 fp2 = fopen(outfile, "w"); 14 while ( (c = fgetc(fp1)) != EOF ) 15 fputc(c,fp2); 16 fclose(fp1); 17 fclose(fp2); 18 return(0); 19 } Notes: * line 14: * fgetc returns the next character from the file * that value is assigned to c * next, that value is compared to EOF * fgetc returns a special value (EOF) when there are no more characters in the file. EOF is usually #define'd to have a value of -1 inside stdio.h * so: the loop stops when fgetc returns EOF * line 15: fputc writes a single character to a file. * Notice that c is an "int" instead of a "char". The "int" type is compatible with type "char". It can be used to store ASCII values. And in this case, we need to use int, because the EOF value (usually -1) is outside the set of acceptable values for type "char" (0 to 127). * Example 3 #include 1 int main(void) 2 { 3 FILE *fp1; 4 FILE *fp2; 5 char infile[25]; 6 char outfile[25]; 7 char s[100]; 8 printf("Enter name of input file: "); 9 scanf("%s", infile); 10 printf("Enter name of output file: "); 11 scanf("%s", outfile); 12 fp1 = fopen(infile, "r"); 13 fp2 = fopen(outfile, "w"); 14 while ( fgets(s,100,fp1) != NULL ) 15 fputs(s,fp2); 16 fclose(fp1); 17 fclose(fp2); 18 return(0); 19 } Notes: * line 14: * fgets gets one line of the file into array s, and adds a \0 at the end * but, as a safety, fgets won't get more than 100 characters. * fgets returns NULL when the end of file is reached * line 15: * fputs writes all the characters in s (up to \0) to the file. * Summary: How to Use Files * Declare a FILE pointer for each file. ex: FILE *in, *out; * Use "fopen" to open each file: ex: in = fopen("input", "r"); out = fopen("output", "w"); * Use "fscanf" and "fprintf" for input and output. ex: fscanf(in, "%d", &x); fprintf(out, "%d", x); * Use "fgetc" and "fputc" for inputting/outputting one character at a time. ex: while ( (c = fgetc(in)) != EOF ) fputc(c,out); * Use "fgets" and "fputs" for inputting/outputting one line at a time. ex: while ( fgets(s,100,in) != NULL ) fputs(s,out); * Use "fclose" to close each file: ex: fclose(in); fclose(out); * A Character, Word and Line Counting Program (modified from "The C Programming Language" by Kernighan and Ritchie) 1 #include 2 #define IN 1 /* inside a word */ 3 #define OUT 0 /* outside a word */ 4 int main(void) 5 { 6 int c, nl, nw, nc, state; 7 char fname[25]; 8 FILE *fp; 9 state = OUT; 10 nl = nw = nc = 0; 11 printf("filename: "); 12 scanf("%s", fname); 13 fp = fopen(fname, "r"); 14 while ( (c = fgetc(fp)) != EOF ) { 15 ++nc; 16 if (c == '\n') 17 ++nl; 18 if (c == ' ' || c == '\n' || c == '\t') 19 state = OUT; 20 else if (state == OUT) { 21 state = IN; 22 ++nw; 23 } 24 } 25 printf("%d %d %d %s\n", nl, nw, nc, fname); 26 } This program does what the Linux program "wc" does. Ex: (of the Linux version of the command) $ wc lec13 355 1465 10549 lec13 * Saving Data to A File 1 #include 2 typedef struct { 3 char name[30]; 4 int score; 5 char grade; 6 } Student; 7 int main () 8 { 9 Student students[100]; 10 FILE *fp; 11 char fname[100]; 12 int i; 13 //not shown: code to fill up students array 14 printf("filename: "); 15 scanf("%s", fname); 16 fp = fopen(fname, "w"); 17 for (i = 0; i < 100; i++) { 18 fprintf(fp,"%s\n",students[i].name); 19 fprintf(fp,"%d\n",students[i].score); 20 fprintf(fp,"%c\n",students[i].grade); 21 } 22 fclose(fp); 23 ... 24 return 0; 25 } * Reading Data Back from a File 1 #include 2 typedef struct { 3 char name[30]; 4 int score; 5 char grade; 6 } Student; 7 int main () 8 { 9 Student students[100]; 10 FILE *fp; 11 char fname[100]; 12 int i; 13 printf("filename: "); 14 scanf("%s", fname); 15 fp = fopen(fname, "r"); 16 for (i = 0; i < 100; i++) { 17 fscanf(fp,"%s\n",students[i].name); 18 fscanf(fp,"%d\n",&students[i].score); 19 fscanf(fp,"%c\n",&students[i].grade); 20 } 21 fclose(fp); 22 return 0; 23 } Data Types in C * main memory * long array of elements * each element is N bits wide (32 is a typical number) * bit = 1 or 0 (byte = 8 bits, nibble = 4 bits) * each element stores an N-bit binary number * each data type has a different size, determined by the specific compiler you are using. For the PC's in the lab: int - 4 bytes char - 1 byte float - 4 bytes double - 8 bytes int * (pointer to int) - 4 bytes char * (pointer to char) - 4 bytes double * (pointer to double)- 4 bytes * other versions of int: short - 2 bytes long - 4 bytes (actually same as int, so not so useful!) * "unsigned" The word "unsigned" can be added before "int" and all its variations, and before "char". ex: unsigned int x; It means "no positive or negative sign". In a regular int, 1 of the 32 bits is used for the + or - sign (for positive or negative numbers). In an unsigned int, that bit can be used for the number itself. Thus, the maximum value of an unsigned int is larger than the max value of a regular int. * Side Note on double: * an int variable contains a 32-bit binary number * a "float" or "double" number is more complicated -- 2 binary numbers are stored: a mantissa (the "base") and an exponent. The number = mantissa * 2^exponent. * Mixing types: C is smart enough to convert a value from 1 type to another to make things work out right. ex: int x; double y, z; x = 4; y = 4.5; z = y + x; // x's value is converted to double * We can force the conversion using a "type cast": ex: double z; int x = 7; int y = 2; z = x / y; // z = 3.0 here z = ( (double) x ) / y; // z = 3.5 here * The (double) in front of x converts x's value to the double type. Then, the type of y's value is converted to double to match. ------------------------------------------------------------ The sizeof operator The sizeof operator returns the size of a variable or data type. Best explained by example: 1 #include 2 typedef struct { 3 char name[30]; 4 int score; 5 char grade; 6 } Student; 7 int main(void) 8 { 9 int x; 10 int y[100]; 11 char c[] = "hello"; 12 printf("size of int: %d bytes\n", sizeof(int)); 13 printf("size of double: %d bytes\n", sizeof(double)); 14 printf("size of x: %d bytes\n", sizeof(x)); 15 printf("size of y: %d bytes\n", sizeof(y)); 16 printf("size of y[0]: %d bytes\n", sizeof(y[0])); 17 printf("size of c: %d bytes\n", sizeof(c)); 18 printf("size of Student: %d bytes\n", sizeof(Student)); 19 return(0); 20 } results: size of int: 4 bytes size of double: 8 bytes size of x: 4 bytes size of y: 400 bytes size of y[0]: 4 bytes size of c: 6 bytes size of Student: 40 bytes Notice that the argument can be the name of a variable, array, or data type! So this is a flexible function. ------------------------------------------------------------