clark cs1713 syllabus lecture notes programming assignments printf This prints output based on a specification. printf(specification, value1, value2, …); The specification contains strings and format codes. Some format codes: %s show a null terminated string (must pass an address) %d show an integer value %ld show a long integer value %f show a floating point value %lf show a double value %e show a floating point value using scientific notation %c show single character %x show a hex value %% show a % %p print a pointer (must pass an address) We use \n to cause the output to do a line feed. A format code can be in the following form: flag minWidth precision lengthModifier code We go over this in more detail later in the semester, but here are some helpful examples: %10.2lf where 10 is the minWidth, 2 is the precision, l is the lengthModifier (long floating point), and f is the code. %.2lf where this is the same as above, but it doesn't have a minWidth. %10s where 10 is the minWidth and s is the code. The value will be right-justified. %-10s where - specifies to left-justify, 10 is the minWidth, and s is the code. The value will be left-justified. %5.10s where 5 is the minWidth, 10 is the maximum width, and s is the code. The value will be right-justified. If the corresponding value is longer than 10 characters, the excess characters will be truncated from the end. homework set up char szName[21] = "Bob Wire"; int iOrderQuantity = 5; double dUnitCost = 7.25; char cGender = 'F'; printf("name is %s\n", szName); printf("Order Quantity is %d\n", iOrderQuantity); printf("Unit cost is %lf\n", dUnitCost); printf("Gender is %c\n", cGender); Output: name is Bob Wire Order Quantity is 5 Unit cost is 7.250000 Gender is F printf("Unit printf("Unit printf("Unit printf("Unit printf("Unit Cost Cost Cost Cost Cost in in in in in 10.2 is '%10.2lf'\n", dUnitCost); 9.3 is '%9.3lf'\n", dUnitCost); .2 is '%.2lf'\n", dUnitCost); -10.2 is '%-10.2lf'\n", dUnitCost); -9.3 is '%-9.3lf'\n", dUnitCost); printf("Name '%10s' and '%-10s'\n", szName, szName); Output: Unit Cost in 10.2 is ' 7.25' Unit Cost in 9.3 is ' 7.250' Unit Cost in .2 is '7.25' Unit Cost in -10.2 is '7.25 ' Unit Cost in -9.3 is '7.250 ' Name ' Bob Wire' and 'Bob Wire ' Exercise: Using the Customer typedef, assume the customerM array has already been populated and the number of customers is in iCustomerCnt. Print an array of customers with a heading and the values in a table format. Hint: use the same fieldwidth for the column heading and the value. Instead of this for the heading: printf("ID Name Balance\n"); use printf("%-6s %-19s %10s\n", "ID", "Name", "Balance"); typedef struct { int iID; // Assume it is 6 digits char szName[20]; // 19 characters double dBalance; // allow 10 digits with 2 to the right of the decim } Customer; Customer customerM[30]; int iCustomerCnt; int i; // assume customerM and iCustomerCnt have been initialized. // print the column heading // print the contents of the array Special constants \n line feed \t tab \f form feed \" double quote \\ back slash \a alert Redirecting output to a file In Unix, you can specify where to direct the standard output by specifying command > filename You can also use fprintf which has an additional parameter for the file. fprintf(file, specification, value1, value2, …); The file should be opened with an fopen(). // Suppose the executable is one.exe. On the command line, // we can specify where to direct the output when we run // the program. one.exe >myOutput.txt #define OUT_FILE "myoutFile.txt" FILE *fileOut; fileOut = fopen(OUT_FILE, "w"); if (fileOut == NULL) { fprintf(stderr, "Could not open %s\n", OUT_FILE); return 2; } fprintf(fileOut, "name is %s\n", szName); fopen FILE *fopen(char *pszFileName, char *pszMode) fopen returns a FILE pointer to the file that was opened or NULL if it wasn't successful. Parameters: pszFileName is the name of the file to open. Sometimes it is necessary to put the full path file name. (e.g., "~/cs1713/examavgInput.txt") pszMode is a string tells fopen how to open the specified file: "r" open file as text stream input. If the file doesn't exist, fopen will return NULL. "w" open file for text stream output. It will create the file if it doesn't already exist and overwrite the file it does already exist. "a" open an existing file to append text to it. "w+" open a file for read and write. "rb" open file as binary input. If the file doesn't exist, fopen will return NULL. "wb" open a file for binary output. "ab" open an existing file to append binary data to it. "wb+" open a file for binary read and write FILE *fileIn; fileIn = fopen("~/cs1713/cs1713p2Input.txt", "r"); if (fileIn == NULL) { fprintf(stderr, "Could not open %s\n" , "~/cs1713/cs1713p2Input.txt"); return 3; // input file error } fgets and scanf These are used to receive stream input. fgets(stringVariable, maxLength, file); This reads from the specified file until either maxLength - 1 characters are read or until a line feed character is encountered. scanf(formatString, address1, address2, …); Facts about scanf(): must be passed addresses since it stores its results in those addresses returns the number of successful conversions from its input to those addresses null terminates resulting strings #include <stdio.h> int main(int argc, char *argv[]) { struct { char szStockNumber[21]; double dInventoryUnitPrice; int iStockCount; } stock; char *pszGetsResult; // result of fgets char szInputBuffer[100]; // entire input line int iScanfCount; pszGetsResult = fgets(szInputBuffer, 100, stdin); if (pszGetsResult == NULL) { printf("ERROR: could not read data file\n"); return 3; // input error } iScanfCount = sscanf(szInputBuffer, "%s %lf %d" , stock.szStockNumber , &stock.dInventoryUnitPrice , &stock.iStockCount); if (iScanfCount < 3) { printf("ERROR: only read %d values\n" , iScanfCount); return 3; } printf("Stock Number = %s, Unit Price = %.2lf, Stock Count = %d\n" , stock.szStockNumber , stock.dInventoryUnitPrice , stock.iStockCount); return 0; // normal exit Problems can be avoided by using fgets to get a line of input data and store it in a buffer. sscanf can be used to scan the data from that buffer and store the results in specified variables. } scanf format codes do not have the same form as printf. There are several forms: maxSize lengthModifier code [acceptValues] [^delimiters] For the first form (maxSize code) of scanf format codes: maxSize specifies the maximum number of characters to read. After scanf sees a non-white space character, the next white space (blank, tab, newline) character will be the delimiter for the value. If you want to skip over a delimiter after you read a value, show the delimiter in the formatString. Blanks in the formatString will match zero to many white space characters. lengthModifier can be a letter l to specify a longer value (e.g., long, double). The values for (lengthModifier and) code include: %s read a string and null terminate it %d read an integer value %ld read a long integer value %f read a floating point value %lf read a double value %e read a floating point value using scientific notation %c read single character %x read a hex value %n receives an integer value of the number of characters read so far Notice that scanf doesn't have a precision. Do not specify %10.2lf. Format codes like "10.2lf" do not work with scanf since it doesn't understand the ".2". Seq 1 2 3 4 5 6 7 8 9 10 11 12 13 szInputBuffer Format Cnt 123456 123 45.67 %s %d %lf 3 123456 123 45.67 %5s %d %lf 3 123456 123 45.67 %[1-9] %d %lf 3 123456 123 45.67 %[1-9],%d,%10lf 1 comma in format didn’t match space 123456,123,45.67 %[1-9],%d,%10lf 3 123456,123,45.67 %[^,],%d,%10lf 3 123456,123,45.67 %6[^,] ,%d,%10lf 3 123456 , 123,45.67 %[^,],%d,%10lf 3 123456 , 123,45.67 %[^, ],%d,%10lf 1 comma in format didn't match first space 123456 , 123,45.67 %[^, ] ,%d,%10lf 3 123456 , 123,45.67 %[^, ] ,%d,%10lf 3 123456 , 123,45.67 %[^, ] ,%d,%10lf 3 123456,123,45.67 %[^,] %d %10lf 1 comma in data isn't a valid numeric value for szV1 '123456' '12345' '123456' '123456' iV2 123 6 123 n/a dV3 45.67 123.00 45.67 n/a '123456' '123456' '123456' '123456 ' '123456' 123 123 123 123 n/a 45.67 45.67 45.67 45.67 n/a '123456' '123456' '123456' '123456' %d 123 123 123 n/a 45.67 45.67 45.67 n/a For second form ([acceptValues]) of scanf format codes: acceptValues is a list of acceptable values. To specify a range of characters, a dash can be used. Some interesting scanf format codes: %[a-z] reads the lower case characters a-z and stops when any other character is read. %[a-zA-Z] reads any alphabetic character and stops when any other character is read. %[^,] reads everything but commas into the corresponding variable. This means that input terminates with a comma instead of a space. %20[^\n] reads everything but line feeds into the corresponding variable. This means that the input terminates with a line feed or \0. It places a maximum of 20 characters (plus a \0) in the variable. // sscanf gets its input from a variable (1st argument) char szLongAddress [] = "123 Dirt Rd\n"; long lStreetNumber; char szStreet[11]; iScanfCount = sscanf(szInputStr, "%ld %10[^\n]\n" , &lStreetNumber , szStreet); Warning!!! Warning !!! Warning !!! scanf() must be passed addresses. Numeric variables pass values instead of addresses. You must pass the address of numeric variables using an &. This is also necessary for single byte variables. Since the addresses of arrays are automatically passed, it isn't necessary to use the & with arrays. int iOrderQuantity; char szCustomerId[10]; iScanfCount = scanf("%s %d", szCustomerId, iOrderQuantity); scanf can overwrite memory!! We didn't show gets(stringVariable) because it is even less safe. It isn't passed the maxLength. fclose fclose(FILE *pfileVariable) is used to close a file, completing the I/O and freeing internal memory used for the file. Since iOrderQuantity is numeric, we must pass its address. In this exam we passed its value which scanf will attempt to use as an address. Depending on that value, it might have an addressing error or store a v at that questionable address. int iOrderQuantity; char szCustomerId[10]; char szAddress[300]; iScanfCount = scanf("%s %d", szCustomerId, &iOrderQuantity); With the data containing "012345678901 100", the value would continue p szCustomerId and corrupt szAddress. Where is the zero byte? See the CommandArg_c.txt for a full example using files.