clark / cs1713 / syllabus / lecture notes / programming assignments / homework / set up
printf
This prints output based on a specification.
printf(specification, value1, value2, …);
The specification contains strings and format codes. Some format codes:
%sshow a null terminated string (must pass an address)
%dshow an integer value
%ldshow a long integer value
%fshow a floating point value
%lfshow a double value
%eshow a floating point value using scientific notation
%cshow single character
%xshow a hex value
%%show a %
%pprint 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.2lfwhere 10 is the minWidth, 2 is the precision, l is the lengthModifier (long floating point), and f is the code.
%.2lfwhere this is the same as above, but it doesn't have a minWidth.
%10swhere 10 is the minWidth and s is the code. The value will be right-justified.
%-10swhere - specifies to left-justify, 10 is the minWidth, and s is the code. The value will be left-justified.
%5.10swhere 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. / charszName[21] = "Bob Wire";
intiOrderQuantity = 5;
doubledUnitCost = 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 Cost in 10.2 is '%10.2lf'\n", dUnitCost);
printf("Unit Cost in 9.3 is '%9.3lf'\n", dUnitCost);
printf("Unit Cost in .2 is '%.2lf'\n", dUnitCost);
printf("Unit Cost in -10.2 is '%-10.2lf'\n", dUnitCost);
printf("Unit Cost in -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"); / typedefstruct
{
intiID; // Assume it is 6 digits
char szName[20]; // 19 characters
double dBalance; // allow 10 digits with 2 to the right of the decimal
} Customer;
Customer customerM[30];
intiCustomerCnt;
inti;
// assume customerM and iCustomerCnt have been initialized.
// print the column heading
??
// print the contents of the array
??
Special constants
\nline feed
\ttab
\fform feed
\"double quote
\\back slash
\aalert
Redirecting output to a file
In unix, you can specify where to direct the standard output by specifying
command > filename / // 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
Redirecting output to a file (continued)
You can also use fprintfwhich has an additional parameter for the file.
fprintf(file, specification, value1, value2, …);
The file should be opened with an fopen(filename, fileMode). / #define OUT_FILE "myoutFile.txt"
FILE *fileOut;
fileOut = fopen(OUT_FILE, "w");
if (fileOut == NULL)
{
fprintf(stderr, "Could not open %s\n", OUT_FILE);
return2;
}
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");
return3; // input file error
}
fgetsand scanf
These are used to receive input from standard input.
fgets(stringVariable, maxLength, file); This reads from standard input until either maxLength- 1 characters are read or until a line feed character is encountered.
scanf(formatString, address1, address2, …);
Facts about scanf():
  • scanf reads from a file
  • 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
  • format codes are typically in the form:
maxSizelengthModifier code
  • Unlike printf(), scanf() doesn't have a precision. You cannot specify %10.2lf for scanf().
/ #includestdio.h
int main(intargc, char *argv[])
{
struct
{
charszStockNumber[21];
doubledInventoryUnitPrice;
intiStockCount;
} stock;
char *pszGetsResult; // result of fgets
charszInputBuffer[100]; // entire input line
intiScanfCount;
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
}
sscanf
We will usually read a line of text into a variable using fgets and then use sscanf to take the data from that variable to populate our target variables.
sscanf(stringVariable, formatString, address1, address2, …);
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. / // The following code reads a line of text until EOF.
// We will then use sscanf to copy the values into variables
// for ABC123 ID and two grades.
// Print that ABC123 ID and the higher of the two grades.
#include <stdio.h
int main(intargc, char *argv[])
{
char szInputBuffer[101];
char szABC123[7];
double dGrade1;
double dGrade2;
intiScanfCount;
printf("%-6s %-6s\n", "ABC123", "Grade");
// Read a line of text until EOF.
// Note that fgets returns NULL when it reaches EOF.
while (fgets(szInputBuffer, 100, stdin) != NULL)
{
iScanfCount = sscanf(szInputBuffer, "%s %lf %lf"
, szABC123
, &dGrade1
, &dGrade2);
if (iScanfCount < 3)
{
printf("Invalid data\n");
return 3; // non-zero value
}
// Print the ABC123 ID and the higher grade
if (dGrade1 > dGrade2)
printf("%-6s %6.2lf\n", szABC123, dGrade1);
else
printf("%-6s %6.2lf\n", szABC123, dGrade2);
}
return 0;
}
scanf format codes do not have the same form as printf. There are several forms:
maxSizelengthModifier 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 (lengthModifierand) code include:
%sread a string and null terminate it
%dread an integer value
%ldread a long integer value
%fread a floating point value
%lfread a double value
%eread a floating point value using scientific notation
%cread single character
%xread a hex value
%nreceives 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".
SeqszInputBuffer Format Cnt szV1 iV2 dV3
1 123456 123 45.67 %s %d %lf 3 '123456' 123 45.67
2 123456 123 45.67 %5s %d %lf 3 '12345' 6 123.00
3 123456 123 45.67 %[1-9] %d %lf 3 '123456' 123 45.67
4 123456 123 45.67 %[1-9],%d,%10lf 1 '123456' n/a n/a
comma in format didn’t match space
5 123456,123,45.67 %[1-9],%d,%10lf 3 '123456' 123 45.67
6 123456,123,45.67 %[^,],%d,%10lf 3 '123456' 123 45.67
7 123456,123,45.67 %6[^,] ,%d,%10lf 3 '123456' 123 45.67
8 123456 , 123,45.67 %[^,],%d,%10lf 3 '123456 ' 123 45.67
9 123456 , 123,45.67 %[^, ],%d,%10lf 1 '123456' n/a n/a
comma in format didn't match first space
10 123456 , 123,45.67 %[^, ] ,%d,%10lf 3 '123456' 123 45.67
11 123456 , 123,45.67 %[^, ] ,%d,%10lf 3 '123456' 123 45.67
12 123456 , 123,45.67 %[^, ] ,%d,%10lf 3 '123456' 123 45.67
13 123456,123,45.67 %[^,] %d %10lf 1 '123456' n/a n/a
comma in data isn't a valid numeric value for %d
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() and sscanf() 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 character variables.
Since the addresses of arrays are automatically passed, it isn't necessary to use the & with arrays. / intiOrderQuantity;
char szCustomerId[10];
iScanfCount = scanf("%s %d", szCustomerId, iOrderQuantity);
Since iOrderQuantity is numeric, we must pass its address. In this example, 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 value at that questionable address.
scanf() and sscanf() can overwrite memory!! / intiOrderQuantity;
char szCustomerId[10];
char szAddress[300];
iScanfCount = scanf("%s %d", szCustomerId, &iOrderQuantity);
With the data containing "012345678901 100", the value would continue past szCustomerId and possibly corrupt szAddress. Where is the zero byte?
fclose
fclose(FILE *pfileVariable) is used to close a file, completing the I/O and freeing internal memory used for the file. / See the CommandArg_c.txt for a full example using files.