C Functions
C++ includes most of what the language C has to offer and that includes the input output functions that predate "cout" and "cin".
File: "i1.cpp"
#include <stdio.h>int main(){ char ch ; printf( "Enter a character:" ) ; ch = getchar() ; printf ( "%c\n" , ch ) ; printf( "A literal string.\n" ) ; printf( "Using format specifiers. %d %d\n" , 5, 10 ) ; int x1 ; printf ( "Enter a number:" ) ; scanf( "%d" , &x1) ; printf( "x1 is %d\n" , x1 ) ; //Input buffer has the end of line character in it //creating a problem. printf ( "Enter a number -number-:" ) ; scanf( "-%d-" , &x1) ; printf( "x1 is %d\n" , x1 ) ; return ( 1) ;}
Output:
$ g++ i1.cpp ; ./a.exe
Enter a character:e
e
A literal string.
Using format specifiers. 5 10
Enter a number:4
x1 is 4
Enter a number -number-:x1 is 4
We notice that we are not given an opportunity to enter the last "scanf" . The way the input works is when the user types in something and hits the "Enter" key the input is stored in a buffer and the "scanf" then reads from the buffer.
The
scanf( "%d" , &x1) ;
read the number from the buffer but left the new line character in there and the next scanf read that. We can correct this in the following program.
File: "i1a.cpp"
#include <stdio.h>#include <string.h>int main(){ char ch ; printf( "Enter a character:" ) ; ch = getchar() ; printf ( "%c\n" , ch ) ; printf( "A literal string.\n" ) ; printf( "Using format specifiers. %d %d\n" , 5, 10 ) ; int x1 ; printf ( "Enter a number:" ) ; scanf( "%d" , &x1) ; printf( "x1 is %d\n" , x1 ) ; //Input buffer has the end of line character in it //creating a problem. getchar() ; //read the end of line character printf ( "Enter a number -number-:" ) ; scanf( "-%d-" , &x1) ; printf( "x1 is %d\n" , x1 ) ; getchar() ; char buffer[256] ; printf( "Enter your full name:" ) ; //Does not read the full name scanf( "%s" , buffer ) ; printf( "%s\n" , buffer ) ; //Clear the buffer scanf( "%s" , buffer ) ; getchar() ; printf( "Enter your full name:" ) ; memset( buffer, 0 , 256 ) ; //Will read the whole line gets ( buffer ) ; printf( "%s\n" , buffer ) ; return ( 1) ;}
The "printf" function has different format specifiers for the place holders. Some of the specifiers are:
%c Character
%d Signed integer
%f Float values
%lf Double
%p Pointer
The "printf" function can also specify widths of the placeholders.
File: "i2.cpp"
#include <stdio.h>int main(){ printf ( "%10s %10s\n" , "Number" , "Square" ) ; for( int i1=1 ; i1 <=5 ; i1++ ) { printf( "%10d %10d\n" , i1 , i1*i1 ) ; } //for //Left justified printf ( "%-10s %-10s\n" , "Number" , "Square of a number" ) ; for( int i1=1 ; i1 <=5 ; i1++ ) { printf( "%-10d %-10d\n" , i1 , i1*i1 ) ; } //for return ( 1) ;}
Output:
$ ./a.exe
Number Square
1 1
2 4
3 9
4 16
5 25
Number Square of a number
1 1
2 4
3 9
4 16
5 25
The below example shows how to use the format specifier for a floating point number.
File: "i3.cpp"
#include <stdio.h>int main(){ float PI = 3.142 ; printf ( "%-10s %-10s\n" , "Radius" , "Area" ) ; for( float i1=1 ; i1 <=5 ; i1++ ) { printf( "%-10.0f %-10.2f\n" , i1 , i1*i1*PI ) ; } //for return ( 1) ;}
Output:
$ ./a.exe
Radius Area
1 3.14
2 12.57
3 28.28
4 50.27
5 78.55
The "printf" and "scanf" have a different form called "sprintf" and "sscanf" used for writing and reading to strings instead of the console.
File: "i4.cpp"
#include <stdio.h>int main(){ char buffer[256] ; int x1 = 0 ; sprintf( buffer , "%d" , 25 ) ; printf( "Buffer %s\n" , buffer ) ; sscanf ( buffer, "%d" , &x1 ) ; printf( "x1: %d\n" , x1 ) ; return ( 1) ;}
Output:
$ ./a.exe
Buffer 25 x1: 25
We can use "sprintf" to convert a number to a string and also
read a number from a string. The function "atoi" can also be used
to convert a string to an integer and "itoa" to convert an integer
to string. However the function "itoa" is not standard and not supported by most compilers. The following code produces a compiler error.
#include <stdio.h>#include <stdlib.h>int main(){ char buffer[256] ; int x1 = 10 ; int y1 = 0 ; itoa( x1, buffer, 10 ) ; printf( "Buffer %s\n" , buffer ) ; y1 = atoi( buffer ) ; printf( "y1: %d\n" , y1 ) ; return ( 1) ;}
The functions can be used to parse a string into different inputs. inputs.
File: "i5.cpp"
#include <stdio.h> #include <stdlib.h> #include <string.h> int main () { int day, year; char weekday[20], month[20], dtm[100]; strcpy( dtm, "Saturday March 25 1989" ); sscanf( dtm, "%s %s %d %d", weekday, month, &day, &year ); printf("%s %d, %d %s\n", month, day, year, weekday ); return(0); }
Output:
$ g++ i5.cpp ; ./a.exe March 25, 1989 Saturday
Exercise
1) Ask the user for 2 integers representing a range ( of Celsius) and then print a table showing the conversion to Fahrenheit with the Celsius values getting incrdmented by 1 . The table should be left justified with 2 decimal points for the Fahrenheit . Also print a heading.
Output should look like:
$ g++ ex1.cpp ; ./a.exe Enter the start range:10 Enter the high range:20 C F 10 50.00 11 51.80 12 53.60 13 55.40 14 57.20 15 59.00 16 60.80 17 62.60 18 64.40 19 66.20 20 68.00
File: "c1.cpp"
#include <iostream>#include <iomanip>using namespace std ;int main(){ cout << "*" << setw(10) << 17 << "*" << endl ; cout << "*" << setw(10) << "Heading1" << "*" << endl ; //setw needs to be applied to each output cout << "*" << "Heading2" << "*" << endl; cout << left << "---------------" << endl ; ; cout << "*" << setw(10) << 17 << "*" << endl ; cout << "*" << setw(10) << "Heading1" << "*" << endl; cout << fixed << setprecision(2) << 3.14159 << endl ; cout << right ; cout << fixed << setprecision(2) << setw(10) << 3.14159 << endl ; return 0;}
Output:
$ g++ c1.cpp ; ./a.exe
* 17*
* Heading1*
*Heading2*
---------------
*17 *
*Heading1 *
3.14
3.14
We also have the same problem with just a single word being read when we do
cin >> str1
#include <iostream>#include <iomanip>using namespace std ;int main(){ string str1 ; cout << "Enter your name." ; cin >> str1 ; cout << str1 << endl ; //Reads the second word cin >> str1 ; cin.get() ; cout << "Enter your name again." ; getline ( cin, str1 ) ; cout << str1 << endl ; return 0;}
Output:
$ g++ c2.cpp ; ./a.exe
Enter your name.Marvin Hagler
Marvin
Enter your name again.Marvin Hagler
Marvin Hagler
File: "c3.cpp"
lude <iostream>
#include <iomanip>#include<limits>using namespace std ;int main(){ int x1 = 0 ; cout << "Enter x1 value." ; cin >> x1 ; cout << x1 << endl ;while(1){ if(cin.fail()) { //clears the error flag cin.clear() ; //Ignore anything else in the buffer cin.ignore( numeric_limits<streamsize>::max() , '\n' ); cout<< "You have entered wrong input."<< endl; cin >> x1 ; } else break ;} cout << "x1:" << x1 << endl ; //Another way .. Does not work cout << numeric_limits<int>::max() << endl ; x1 = numeric_limits<int>::max() ; while ( x1 == numeric_limits<int>::max() ) { cout << "Enter x1 value." ; cin >> x1 ; //x1 is 0 at this point cout << x1 << endl ; } //while return 0;}
Exercise
2) Repeat the exercise 1 to use cin and cout instead.
2a)
#include <iostream>#include <iomanip>using namespace std ;int main(){ string str1 ; cout << "Enter a word." ; cin >> str1 ; cout << "first input:"<< str1 << endl; cout << "Enter a line." ; getline(cin, str1 ) ; cout << "line input:" << str1 << endl ; return 0;}
The above program skips "getline" call. Explain why the problem occurs and correct it by using the "cin.get()" function call.
There is nothing special about "cout". It is a class that someone wrote. We can also write a similar class ourselves.
File: "c4.cpp"
#include <iostream>#include <iomanip>#include<limits>using namespace std ;class mycout { public: static string myendl ; mycout& operator<<( int& x1) { printf ( "%d" , x1 ) ; return ( *this ) ; } mycout& operator<<(const char* str1) { printf ( "%s" , str1 ) ; return ( *this ) ; } mycout& operator<<(string& str1) { printf ( "%s" , str1.c_str() ) ; return ( *this ) ; }};string mycout::myendl = "\n" ;int main(){ int x1 = 0 ; mycout obj1 ; string str1 = "Another String" ; obj1 << x1 << " Test some string\n" ; obj1 << str1 ; obj1 << mycout::myendl << mycout::myendl ; return 0;
Both text and binary files store 0's and 1's .
A text file has characters with the range of 0 to 127 while a binary file will have characters within the range of
0 to 255 . A text file can be thought of something we can open with an editor . If we open a binary file with an editor then we will see gibberish on the screen.
On the unix system we can see a file in it's binary form with the command:
hexdump -C nameOfFile
Sample Output:
[amittal@hills InputOutput]$ hexdump -C demofile.txt
00000000 42 61 63 68 0a 42 65 65 74 68 6f 76 65 6e 0a 4d |Bach.Beethoven.M|
00000010 6f 7a 61 72 74 0a 53 63 68 75 62 65 72 74 0a 42 |ozart.Schubert.B|
00000020 61 63 68 0a 42 65 65 74 68 6f 76 65 6e 0a 4d 6f |ach.Beethoven.Mo|
00000030 7a 61 72 74 0a 53 63 68 75 62 65 72 74 0a |zart.Schubert.|
Each character is shown in 2 hexadecimal characters. Let us run the same command on a binary file.
[amittal@hills InputOutput]$ hexdump -C a.out | more
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 d0 08 40 00 00 00 00 00 |..>.......@.....|
00000020 40 00 00 00 00 00 00 00 40 1d 00 00 00 00 00 00 |@.......@.......|
00000030 00 00 00 00 40 00 38 00 09 00 40 00 1f 00 1e 00 |....@.8...@.....|
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000050 40 00 40 00 00 00 00 00 40 00 40 00 00 00 00 00 |@.@.....@.@.....|
We can see that some of the character in the binary output such as "d0" ( Decimal 208 ) are greater than 127 .
Text files will usually be terminated by end of line character and upon opening the file or printing the file we will see line by line output.
Textpad is an editor that can open files in text or binary mode and can be used to see the underlying characters of a file.
Binary files will usually hold the internal representation of data. Let's assume we have a C program with a variable
"x1"
int x1 = 2134562 ;
The variable holds a large number 2 million and something. When this is written to a text file it is written as is with 7 characters. Remember an int in "C" is usually represented by 4 bytes which contains the corresponding binary number.
Converting the above number gives us:
In hex
â€00 20 92 22‬
The above 4 bytes is what will get written to the binary file. In fact any integer will always be written as 4 bytes.
File: "f1.cpp"
#include <stdio.h> int main() { FILE* cfPtr ; if ( (cfPtr = fopen( "data1.txt" , "wb" ) ) == NULL ) { printf( "File could not be opened.\n" ); } else { for( int i1=100 ; i1 <= 110 ; i1++ ) { fwrite( &i1, sizeof( i1 ), 1, cfPtr ) ; } fclose ( cfPtr ); /* fclose closes the file */ } return 0; }
Reading the values back from the data file.
#include <stdio.h> int main() { FILE* cfPtr ; int x1 ; if ( (cfPtr = fopen( "data1.txt" , "rb" ) ) == NULL ) { printf( "File could not be opened.\n" ); } else { for( int i1=100 ; i1 <= 110 ; i1++ ) { fread( &i1, sizeof( i1 ), 1, cfPtr ) ; printf( "Value read was: %d\n" , i1 ) ; } fclose ( cfPtr ); /* fclose closes the file */ } return 0; }
The above shows how we can read the binary values back. Let us write the numbers in text format.
#include <stdio.h> int main() { FILE* cfPtr ; if ( (cfPtr = fopen( "data3.txt" , "w" ) ) == NULL ) { printf( "File could not be opened.\n" ); } else { for( int i1=100 ; i1 <= 110 ; i1++ ) { fprintf( cfPtr, "%d\n" , i1 ) ; } fclose ( cfPtr ); } char buffer[100] ; if ( (cfPtr = fopen( "data3.txt" , "r" ) ) == NULL ) { printf( "File could not be opened.\n" ); } else { //Get one line fgets( buffer ,100, cfPtr ) ; printf( "%s\n" , buffer ) ; //Another way. int y1 ; fscanf( cfPtr, "%d" , &y1 ) ; printf( "%d\n" , y1 ) ; fscanf( cfPtr, "%d" , &y1 ) ; printf( "%d\n" , y1 ) ; fclose ( cfPtr ); } return 0; }
Dealing with strings. The approach is similar to the example above.
#include <stdio.h>//Text data int main() { FILE* cfPtr ; if ( (cfPtr = fopen( "data2.txt" , "w" ) ) == NULL ) { printf( "File could not be opened.\n" ); } else { fputs( "This is a line.\n" , cfPtr) ; fprintf( cfPtr, "This is the second line.\n" ) ; fclose ( cfPtr ); } char buffer[100] ; if ( (cfPtr = fopen( "data2.txt" , "r" ) ) == NULL ) { printf( "File could not be opened.\n" ); } else { fgets( buffer ,100, cfPtr ) ; printf( "%s\n" , buffer ) ; //Problem because of spaces //Will read only one line fscanf( cfPtr, "%s" , buffer ) ; printf( "%s\n" , buffer ) ; fclose ( cfPtr ); } return 0; }
Exercise
3)
Rewrite exercise 1 to take the range as input but instead of writing to the console; write the values to a file named "conversion.txt".
Writing class objects to file.
#include <stdio.h> class student { public: int id ; int grade ; }; int main() { FILE* cfPtr ; if ( (cfPtr = fopen( "students.txt" , "wb" ) ) == NULL ) { printf( "File could not be opened.\n" ); } /* end if */ else { struct student studentObject ; for( int i1=1 ; i1 <= 10 ; i1++ ) { studentObject.id = i1 ; studentObject.grade = 10 + i1 ; fwrite( &studentObject, sizeof( studentObject ), 1, cfPtr ) ; } fclose ( cfPtr ); /* fclose closes the file */ } /* end else */ if ( (cfPtr = fopen( "students.txt" , "rb" ) ) == NULL ) { printf( "File could not be opened.\n" ); } /* end if */ else { student studentObject ; int no ; printf( "Enter the record#:" ) ; scanf( "%d" , &no ) ; fseek( cfPtr, sizeof( studentObject) * (no-1), SEEK_SET ) ; fread( &studentObject, sizeof( studentObject) ,1, cfPtr ) ; printf( "Student Id: %d Grade: %d\n" , studentObject.id , studentObject.grade ) ; fclose ( cfPtr ); } return 0; }
We can write and read data using the "open" function which is defined as a standard C library functions for the Unix system.
File: "open1b.cpp"
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int main(int argc, char *argv[]){ int fd; int n; fd = open("data4.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644); n1 = 1; write(fd, &n1, 4); n1 = 2; write(fd, &n1, 4); n1 = 3; write(fd, &n1, 4); n1 = 4; write(fd, &n1, 4); n1 = 5; write(fd, &n1, 4); n1 = 6; write(fd, &n1, 4); n1 = 7; write(fd, &n1, 4); n1 = 8; write(fd, &n1, 4); n1 = 9; write(fd, &n1, 4); close(fd);}
The above writes some integers to a file named "data.txt" . The "open" call takes the name of the file as the first parameter and flags as the second parameter. Here we are specifying "O_WRONLY" to indicate write only , "O_CREAT" to specify create and "O_TRUNC" indicates that if the file exists it will be truncated to size 0 . The third parameter ( sometimes optional ) indicates the file permissions for this file. The write call is of the form:
write(fd, &n, 4);
The first argument is the file descriptor returned from the "open" call and the second argument is the address of the variable. The third argument is the number of bytes we want written.
We can also write the data in a text format as shown by the below program.
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <string.h>int main(int argc, char *argv[]){ char buffer[256] ; int fd ; sprintf(buffer, "%s %d\n" , "Writing text to file." , 100 ) ; fd = open("data5.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644); write( fd , buffer , strlen( buffer ) ) ; close(fd);}
Exercise
4) Rewrite exercise 1 to take the range as input but instead of writing to the console; write the values to a file named "conversion.txt" using the open call.
//-------------------------------------------------------------
There are 2 kinds of file access methods. One is sequential and the other random. In the sequential method data is first read from the beginning of the file in a sequential manner. If we need to read some data In the random access method we are allowed to read data from any position in the file .
Writing to a file
To write data to a file:
// This program writes data to a file.
#include <iostream>#include <fstream>using namespace std;int main(){ int x1 ; ofstream outputFile; outputFile.open("demofile.txt"); cout << "Now writing data to the file.\n"; // Write four names to the file. outputFile << "Bach\n"; outputFile << "Beethoven\n"; outputFile << "Mozart\n"; outputFile << "Schubert\n"; x1 = 100 ; outputFile << x1 << endl ; // Close the file outputFile.close(); cout << "Done.\n"; return 0;}
To write data to a file we create an "ofstream" object. The type "ofstream" is from the standard template library and that means it's a class and is not part of the C++ language feature. What that means is that someone wrote the class using C++ . The object "outputFile" is an instance of the "ofstream" object and can be used the way "cout" is used. The statement:
outputFile << "Bach\n";
will write "Bach" to the file and will also write the end of line character "\n" to the file. After running the above program our "demofile.txt" will contain:
Bach
Beethoven
Mozart
Schubert
100
Instead of the following 2 statements:
ofstream outputFile;
outputFile.open("demofile.txt");
We can also write the above in one statement
ofstream outputFile("demofile.txt") ;
The above states that "outputFile" object is of type "ofstream" and will open the file "demofile.txt" . Below program shows how this is used:
// This program writes data to a file.#include <iostream>#include <fstream>using namespace std;int main(){ int x1 ; ofstream outputFile("demofile.txt") ; cout << "Now writing data to the file.\n"; // Write four names to the file. outputFile << "Bach\n"; outputFile << "Beethoven\n"; outputFile << "Mozart\n"; outputFile << "Schubert\n"; x1 = 100 ; outputFile << x1 << endl ; // Close the file outputFile.close(); cout << "Done.\n";return 0;}
The above code will create the file "demofile.txt" every time it's run. What if we wanted to append data instead. The "ofstream" object has an open method that can take an additional paramter "ofstream::app" telling it to append to the existing file instead of creating a new one. The below code shows how to do this:
// This program writes data to a file.#include <iostream>#include <fstream>using namespace std;int main(){ int x1 ; ofstream outputFile ; outputFile.("demofile.txt", ofstream::app) ; cout << "Now writing data to the file.\n"; // Write four names to the file. outputFile << "Bach\n"; outputFile << "Beethoven\n"; outputFile << "Mozart\n"; outputFile << "Schubert\n"; x1 = 100 ; outputFile << x1 << endl ; // Close the file outputFile.close(); cout << "Done.\n"; return 0;}
Reading from a file
Data can be read from a file using the "ifstream" class. Suppose there is a file called "friends.txt". Contents of the file are:
//Friends.txt
John
Patrick
Lee
Williams
// This program reads data from a file.#include <iostream>#include <fstream>using namespace std;int main(){ ifstream inputFile; string name; inputFile.open("friends.txt"); cout << "Reading data from the file.\n"; inputFile >> name; // Read name 1 from the file cout << name << endl ; inputFile >> name ; // Read name 2 from the file cout << name << endl ; inputFile.close() ;return ( 1) ;}
Reading a line from a file
#include <iostream>#include <fstream>using namespace std;int main(){ ofstream outputFile ; ifstream inputFile ; int number ; string word ; outputFile.open("data6.txt"); cout << "Now writing data to the file.\n"; // Write four names to the file. outputFile << "We are in a C++ class." << endl ; outputFile << "What" << endl ; outputFile << "fun." << endl ; outputFile.close() ; // Open the file. inputFile.open("data6.txt"); // If the file successfully opened, process it. if (inputFile) { cout << "Inside if condition." << endl ; inputFile >> word ; cout << word << endl ; inputFile >> word ; cout << word << endl ; inputFile >> word ; cout << word << endl ; getline( inputFile, word ) ; cout << word << endl ; // Close the file. inputFile.close(); } else { // Display an error message. cout << "Error opening the file.\n"; } //ifreturn 0;} //main
Writing binary data.
#include <iostream>#include <fstream>using namespace std;int main(){ ofstream outputFile ; ifstream inputFile ; int number ; string word ; int x1 = 100 ; outputFile.open("data7.txt"); cout << "Now writing data to the file.\n"; outputFile.write( (const char*)&x1, sizeof( x1 ) ) ; outputFile.close() ;return 0;} //main
Exercise
5) Rewrite exercise 1 to take the range as input but instead of writing to the console; write the values to a file named "conversion.txt" using the open call.
6) Rewrite the student example to use fstream .