Lecture09: Global Variables, File I/O, and Variable-Length Arguments 5/16/2012 Slides modified from Yin Lou, Cornell CS2022: Introduction to C 1 Administration • Assignment #8 is on the course homepage and due 5/23. 2 Four Items • • • • Global vs. local variables File I/O <ctype.h> Variable length arguments 3 Local vs. Global Variables • The scope of a declaration is the block of code where the variable is valid for use. • A global variable(declaration) is outside the main program. – Normally grouped with other global declarations and at the beginning of the program file. • A local variable (declaration) is inside the body of a function. – Locally declared variables cannot be accessed outside of the function they were declared in. – Possible to declare the same identifier name in different parts of the program. 4 Example int y = 38; // global variable double x; void f(int, int); void main( ) { int z=47; // local variable while(z<400) { int a = 90; z += a++; z++; } y = 2 * z; f(1, 2); } void f(int s, int t) { int r = 12; int z = 27; s = r + t + y; s += z; } 5 Global Variables • Undisciplined use of global variables may lead to confusion and debugging difficulties. – Example? • Instead of using global variables in functions, try passing local variables by reference. File I/O • Before a file can be read or written, it has to be opened by the library function fopen. fopen takes an external name like data.txt, does some housekeeping and negotiation with the operating system, and returns a pointer to be used in subsequent reads or writes of the file. • This pointer points to a structure FILE. FILE *fp; fopen FILE *fopen(char *name, char *mode); void fclose(FILE* stream) • fopen returns a pointer to a FILE. • FILE is a type name. It is defined with a typedef. • mode can be – – – – r - read w - write a - append a “b” can be appended to the mode string to work with binary files. For example, “rb” means reading binary file. Text Files - fprintf and fscanf • int fprintf(FILE *fp, char *format, ...); • int fscanf(FILE *fp, char *format, ...); • int feof(FILE *fp); // return 1/0 end-of-file is reached • Similar to printf and scanf. Example – create and write to a file #include <stdio.h> int main() { FILE *fp; char name[10]; double balance; int account; if ((fp = fopen(“clients.dat”, “w”)) == null) { printf(“File could not be opened\n”); } else { printf(“Enter one account, name, and balance.\n”); scanf(“%d%s%lf”, &account, name, &balance); fprintf(fp, "%d %s %.2f\n", account, name, balance); fclose(fp); } return 0; } Example – read from a file #include <stdio.h> int main() { FILE *fp; char name[10]; double balance; int account; if ((fp = fopen(“clients.dat”, “r”)) == null) { printf(“File could not be opened\n”); } else { fscanf(fp, “%d%s%lf”, &account, name, &balance); printf("%d %s %.2f\n", account, name, balance); fclose(fp); } return 0; } Binary Files - fread and fwrite size_t fread(void *array, size_t size, size_t count, FILE *fp); size_t fwrite(void *array, size_t size, size_t count, FILE *fp); • array must be a pointer • size - size of elements in this array • count - number of elements in this array Example #include <stdio.h> int main() { FILE *fp; float value[3]; fp = fopen(“account.txt”, "rb"); fread(value, sizeof(float), 3, fp); printf("%f\t%f\t%f\n", value[0], value[1], value[2]); fclose(fp); return 0; } Example #include <stdio.h> int main() { FILE *fp; float value[3] = {1.0, 2.0, 3.0}; fp = fopen(“account.txt”, “wb"); fwrite(value, sizeof(float), 3, fp); fclose(fp); return 0; } Example #include <stdio.h> int main() { FILE *fp; float value[300] = {1.0, 2.0, 3.0}; fp = fopen(“account.txt”, “wb"); fprintf(fp, “%lf %lf %lf\n”, value[0], value[1], value[2], …); // fwrite(value, sizeof(float), 300, fp); fclose(fp); return 0; } getchar() & putchar() #include <stdio.h> #include <ctype.h> int main() { int c; while ((c = getchar()) != EOF) { putchar(tolower(c)); } return 0; } <ctype.h> includes many useful functions. The argument for these functions is a single char. Table 7.1. ctype.h character-testing functions. Name True If Argument Is isalnum() Alphanumeric (alphabetic or numeric) isalpha() Alphabetic iscntrl() A control character, such as Ctrl+B isdigit() A digit isgraph() Any printing character other than a space islower() A lowercase character isprint() A printing character ispunct() A punctuation character (any printing character other than a space or an alphanumeric character) isspace() isupper() A whitespace character: space, newline, formfeed, carriage return, vertical tab, horizontal tab, or, possibly, other implementation-defined characters An uppercase character isxdigit() A hexadecimal-digit character Table 7.2. ctype.h character-mapping functions. Name Action tolower() If the argument is an uppercase character, returns the lowercase version; otherwise, just returns the original argument toupper() If the argument is a lowercase character, returns the uppercase version; otherwise, just returns the original argument Variable-length Argument Lists • Let's implement a minimal version of printf. • Use “...” to indicate that the number and types of these arguments may vary. • The declaration “...” can only appear at the end of an argument list. void minprintf(char *format, ...) What Do We Need? • type va_list - declare a variable that will refer to each argument in turn, assume ap • macro va_start - initialize ap to point to the rst unnamed argument • function va_arg - Each call of va_arg returns one argument and steps ap to the next; va_arg uses a type name to determine what type to return and how big a step to take. • function va_end - do whatever cleanup is necessary. It must be called before the program returns. #include <stdarg.h> void minprintf(char *format, ...) { va_list ap; // points to each unnamed arg in turn char *p, *sval; int ival; va_start(ap, format); // make ap point to 1st unnamed arg for (p = format; *p; ++p) { if (*p != '%') { putchar(*p); continue; } switch (*++p) { case 'd': ival = va_arg(ap, int); printf("%d", ival); break; case 's': for (sval = va_arg(ap, char *); *sval; ++sval) { putchar(*sval); } break; default: putchar(*p); } } va_end(ap); // clean up when done } What Do We Need? • type va_list - declare a variable that will refer to each argument in turn, assume ap • macro va_start - initialize ap to point to the rst unnamed argument • function va_arg - Each call of va_arg returns one argument and steps ap to the next; va_arg uses a type name to determine what type to return and how big a step to take. • function va_end - do whatever cleanup is necessary. It must be called before the program returns.