Do I Need to Clear a String Before Using Getline Again

CS330 C++ File I/O and Parsing Line Input


Highlights of this lab:

  • C++ File IO
  • Reading a Line from Input
  • C String Versus String
  • Splitting C Strings into Tokens
  • Dynamic Arrays of C Strings
  • Review of Creating a Class in C++
  • References

C++ File IO

There are three predefined streams in C++:

  • cin
  • cout
  • cerr

Note: brand sure y'all have #include<iostream> and take used "using namespace std;" at the first of the program.

To open a file for reading, you tin utilize code like the post-obit:

ifstream inFile("name", ios::in);

To open a file for output, you tin can utilise code like:

ofstream outfile("name", ios::out);

Make sure you have #include<fstream> before using these functions.

To input a character from an input stream, use the get() function:

char ch; inFile.become(ch);

To output a character, utilise the put() part:

outFile.put(ch);

Here is a sample program that gets characters from standard input and puts them into the file copy.out

#include <fstream>  int master() {    //open up a file copy.out for output    ofstream outFile("copy.out");     if (! outFile)    {       cerr << "cannot open \"copy.out\" for output\n";       return -1;    }     char ch;    while (cin.become(ch))       outFile.put(ch); }      
To open a file for input merely, an ifstream class object is used.
#include <fstream>  int principal() {    cout << "filename: ";    cord file_name;    cin >> file_name;     //open a file copy.out for input    ifstream inFile(file_name.c_str() );     if (! inFile)    {       cerr << "unable to open input file: " 	   << file_name << " --bailing out! \n";       return -ane;    }     char ch;    while (inFile.go(ch))       cout.put(ch); }      

Reading a Line from Input

The above section described unmarried character I/O. Oftentimes y'all want to read a line at a time. The function to do that is getline. There are two versions of getline:

  1. For reading C strings.
    The prototypes are:
    istream& getline (char* southward, streamsize n); istream& getline (char* s, streamsize due north, char delim);          
    For the latter image, if y'all want your lines to be delimited by something other than than a '\n' (the default), then you can specify this as a third, delim, argument. The post-obit is an example that uses the first prototype to read a line at a time of a file and echo information technology to standard output:
    #include <iostream> #include <fstream> using namespace std;  const int MAXLINE=256;  int main() {    ifstream inFile ("test.txt");    char oneline[MAXLINE];     while (inFile)    {        inFile.getline(oneline, MAXLINE);        cout << oneline << endl;    }     inFile.close();     render 0; }
    Notes:
    • the C cord getline is a member function (you use inFile.getline).
    • the second argument is the number of characters you tin can read in. It will only always read in upward to MAXLINE - 1 so that there is room to store '\0' in the last spot of the character assortment.
    • if y'all run across a line that is more than than 256 characters, reading from the file will finish. (Yous tin can use member function, clear, to continue reading).

  2. For reading strings.
    The prototypes are:
    istream& getline (istream& is, string& str); istream& getline (istream& is, string& str, char delim);          
    In one case again, you tin can specify a delimiter other than '\n'. The following is an instance that uses the first epitome to read ane line at a time and echo it to standard output:
    #include <iostream> #include <fstream> #include <string> using namespace std;  int master() {     ifstream inFile("test.txt");     string strOneLine;      while (inFile)     {        getline(inFile, strOneLine);        cout << strOneLine << endl;     }      inFile.close();      return 0; }          
    Notes:
    • getline for reading strings is useful if yous doubtable that yous volition accept longer lines, since strings are dynamically allocated.
    • this getline is implemented as a global part instead of equally member of the stream class

C String Versus String

It's probably been a long time since you've thought about C strings and strings. The following sections is meant to requite yous a review on these two programming topics.

C Strings

C strings are based on the "old" C mode of creating a string. Just because the give-and-take old is used doesn't hateful that C strings aren't used and useful. There are times and places where yous encounter C strings and it's very practiced to know these foundations.

A C string is an array of characters that is null terminated. Functions that are used with C strings include:

  • strlen(const char *s)

Returns the length of the string s (the length does not include the terminating zippo grapheme)
  • strcpy(char *s1, const char *s2)

Copies the string s2 into string s1, including the terminating null character. The developer must ensure that s1 points to enough infinite to hold the effect.
  • strncpy(char *s1, const char *s2, size_t n)

Copies n characters (or until the null terminator has been encountered) from string s2 to cord s1. If s2 has less than n characters, then s1 will be padded with '\0' up to n.

The post-obit code provides examples of dissimilar ways of creating C strings and the use of the functions listed above:

#include <iostream> #include  <cstring> using namespace std;  int main() {    char s1[4]="one"; //remember there will be 1 space for null terminator    char s2[]="two";    char s3[iv];    char *s4;         //s4 will point to the beginning of the assortment of chars    char s5[6];     //Assigning characters to s3    s3[0]='b';    s3[1]='a';    s3[two]='t';    s3[3]='\0';      //Demand to classify space otherwise become core dump when do strcpy. Two ways:    //s4=new char[6];               //specify size directly    s4=new char[strlen("hello") + 1];   //use strlen to make up one's mind size     //Re-create the strings    strncpy(s4,"hello",6);        // specify the size of the string + one for nada       //s5="bye";   // 21: fault: ISO C++ forbids assignment of arrays. Instead:    strncpy(s5, "bye", (strlen("bye") + 1));      cout << s1 << endl;    cout << s2 << endl;    cout << s3 << endl;    cout << s4 << endl;    cout << s5 << endl;     //clean up space allocated for s4    delete [] s4;     return 0; }      

The output:

1 ii bat hello bye      

The following is a diagrammatic representation of the C Strings created in the higher up program:

A POSIX Shortcut

This snippet from the instance above:

        s4=new char[strlen("hello") + 1];   //use strlen to determine size    //Copy the strings    strncpy(s4,"hello",half-dozen);        // specify the size of the string + 1 for cipher      //...     delete[] s4;      
or the C version:
        s4= (char*)malloc(strlen("hello") + i);   //use strlen to determine size    //Copy the strings    strncpy(s4,"how-do-you-do",6);        // specify the size of the cord + 1 for nada     //...     free(s4);      
is and so common that an efficient shortcut was included in the POSIX standards. It is not a part of the C or C++ standard. If you are lucky enough to be programming on a POSIX compliant OS such as Linux (the lab) or Solaris (Hercules) or Mac Bone 10 10.5 then you lot can simplify the snippet above with this function:
  • strdup(const char *s)

returns a arrow to a new string that is a duplicate of the string pointed to by s. The returned pointer should be released with free() because the infinite for the new string is obtained using malloc. If the new string cannot be created, a nada arrow is returned.

The above snippets would then expect like this:

        s4=strdup("hello");   //make copy of "hi"     //...     gratis(s4);      
and considering at that place is only one function call instead of three, the compiled code is likely more than efficient.

Notes:

  • When you classify space for a character assortment, e'er recollect to count the infinite taken up by the null terminator "\0"
  • You lot cannot do assignment as in:
    char s5[half-dozen];     s5="bye"; // **WRONG**
    Y'all must instead use the strncpy function. (Or the strdup function if it is available.)
  • Don't forget to release any memory you request while copying strings later you are done using it.
  • In C code, when you use C String functions, you will use
    #include <cord.h>
    In C++, when you use C Cord functions, you lot volition run across instead:
    #include <cstring>
  • In C lawmaking, when y'all use malloc and free functions, you volition use
    #include <stdlib.h>
    In C++, when you use malloc and free y'all will see instead:
    #include <cstdlib>

Strings

In C++, strings are objects. As such, the functions associated with strings are fellow member functions (such equally str.length()). The post-obit lawmaking provides example of the unlike ways that y'all tin create strings (with different constructors):

#include <iostream> #include <string> using namespace std; // For a list of constructors see: // http://www.cppreference.com/cppstring/string_constructors.html  int chief() {    string str1="one";    cord str2("ii");    string str3;    string str4(str1);    string str5(8,'a');    string str6(str2,i);    string str7(str2,ane,1);     str3="hello";     //bear witness the utilise of the length role    cout << "The length of '" << str3 << "' is: " << str3.length() << endl;     //bear witness the apply of the append part    cout << "str6 earlier: " << str6 << endl;    //The version of append used here is:    //cord& append( const cord& str, size_type index, size_type len );    str6.append(str1,1,one);    cout << "str6 after: " << str6 << endl;     //bear witness the utilise of the + (concatenation) operator    cout << "str1 before: " << str1 << endl;    str1=str1 + ", " + str2;    cout << "str1 after: " << str1 << endl;     cout << str1 << endl;    cout << str2 << endl;    cout << str3 << endl;    cout << str4 << endl;    cout << str5 << endl;    cout << str6 << endl;    cout << str7 << endl;     return 0; }

The output:

The length of 'hello' is: v str6 before: wo str6 after: won  str1 before: one str1 after: one, two  one, ii 2 hello one aaaaaaaa won westward      

Notes:

  • With C++ strings you lot practice not have to worry about allocating space and ending the string with the null terminator.
  • Yous can nevertheless travel through the string using the alphabetize notation as in:
                cout << "Cycling through i character at a fourth dimension" << endl;    for(int i=0; i<str1.length(); i++)    {       cout << str1[i];    }
  • If you ever desire to (which you might want to for this lab exercise--HINT HINT), y'all can use a function c_str to change a string into a character array:
                string str3;     str3= "howdy";     char *cstr2;    cstr2=new char[str3.length() + 1];      strncpy(cstr2, str3.c_str(), (str3.length() + 1));    cout << "cstring2 " << cstr2 << endl <<endl;         //At end, clean up space allocated for cstr2    delete [] cstr2;

Splitting C Strings into Tokens

Sometimes you may desire to split a line into tokens or words. To do that, there is a C String role called strtok. The paradigm is:
char * strtok (char * str, const char * delimiters)
where str is the line (or C cord) that you want to split into tokens or words, and delimiters are an assortment of characters in which any one of the characters delimits or marks the boundaries betwixt words.

The following is an example of using strtok:

#include <iostream> #include <cstring> using namespace std;  int main(int argc, char *argv[]) {    char cstr1[]="This is a sample string. Is it working?";    char delim[]=" ,.-;!?";    char *token;     cout << "cstr1 before being tokenized: " << cstr1 << endl << endl;     //In the first call to strtok, the start argument is the line to be tokenized    token=strtok(cstr1, delim);    cout << token << endl;      //In subsequent calls to strtok, the start argument is NULL    while((token=strtok(NULL, delim))!=Nada)    {          cout << token << endl;    } }

The output:

cstr1 before beingness tokenized: This is a sample string. Is information technology working?  This is a sample string Is information technology working      

There are a couple of "catches" with strtok:

  1. In the first call to strtok, the first argument is the line or C string to exist tokenized; in subsequent calls to strtok, the get-go argument is NULL. Observe the ii calls from the lines to a higher place:
    • token=strtok(cstr1, delim)
    • token=strtok(Nix, delim)
  2. The original C string is modified when it is tokenized so that delimiters are replaced by null terminators ('\0'). The following represents what the C string in the sample lawmaking will look similar after tokenizing:

Dynamic Arrays of C Strings

Sometimes you desire to have a dynamically created array of C Strings. The following code demonstrates this:

#include <iostream> #include <cstring> using namespace std;  int chief () {   char **words;   char endWord[]="330!";    words = new char *[four]; //allocate pointers to 4 words    //words[0] to words[2] are assigned constant strings.  For variable   //assignment, you should allocate space and then use strncpy    //(as done for words[3])   words[0] = "hi";   words[1] = "there";   words[2] = "CS";    words[three] = new char[strlen(endWord) +ane];   strncpy(words[3],endWord,(strlen(endWord)+one));    for (int i=0; i<4; i++)   {      cout << words[i] << endl;   }    //Make clean upwardly everything that you allocated:   delete [] words[3];  // cleans upward words[three]= new char[strlen(endWord +1];    delete [] words;     // cleans up words = new char *[iv]; }

Review of Creating a Grade in C++

In previous computer science classes, you have learned that the typical design of C++ programs is to have two files when you create a form:

  • .h file -- provides an overview of the class including the public and individual members. Typically only the prototypes of the functions are in here.
  • .cpp file -- provides the implementation of the functions

Once y'all have the class defined, then yous need a primary role to exam the code. Good programming practice involves putting the main function in a split up file. This makes a total of iii files.

If you have been working in Java or whatsoever other programming languages, you may be foggy on the C++ syntax. The post-obit is an example of a Circle class with a main.cpp file used to test this code.

circumvolve.h

#include <iostream> using namespace std; #ascertain PI three.14159  grade Circle {    public:       //Constructors       Circle();       Circumvolve(double radius);        //Functions       double getRadius();       istream &readRadius(istream& is);       void setRadius(double radius);       double getArea();       double getCircumference();     private:       double radius; };

circumvolve.cpp

#include "circumvolve.h"  //Constructors. If no radius is specified, the default is five. Circle::Circle() {    radius = five.0; } Circle::Circle(double radius) {    //because the data fellow member is too called radius, you need to utilize "this->"    this->radius=radius; }   //Functions double Circle::getRadius() {    return radius; }  //Read the radius from some input stream (for example cin or an ifstream object) istream& Circle::readRadius(istream& is) {    is >> radius;    return is; }  void Circle::setRadius(double radius) {    this->radius=radius; }  double Circle::getArea() {    return (PI*radius*radius); }  double Circle::getCircumference() {    return (ii*radius*PI); }

primary.cpp

#include "circle.h" #include <iostream> using namespace std;  int master() {    Circle c1;    Circle c2(twenty.2);    Circumvolve c3;     cout << "Please Enter the radius for c3:  ";
c3.readRadius(cin);
cout << endl << "Details of c1:" << endl; cout << "Radius is: " << c1.getRadius() << endl; cout << "Area is: " << c1.getArea() << endl; cout << "Circumference is: " << c1.getCircumference() << endl; cout << endl << "Details of c2:" << endl; cout << "Radius is: " << c2.getRadius() << endl; cout << "Area is: " << c2.getArea() << endl; cout << "Circumference is: " << c2.getCircumference() << endl; cout << endl << "Details of c3:" << endl;
cout << "Radius is: " << c3.getRadius() << endl;
cout << "Area is: " << c3.getArea() << endl;
cout << "Circumference is: " << c3.getCircumference() << endl; return 0; }

To compile and run this code, yous tin use the post-obit commands on the command-line:

  • g++ -c principal.cpp
  • 1000++ -c circle.cpp
  • thou++ -o circle main.o circle.o
  • circumvolve

Notes:

  • recall the semicolon after the closing curly subclass in the .h file
  • call back the ClassName::functionName syntax in the .cpp file

References

  • http://www.cplusplus.com/reference/iostream/istream/getline.html -- more nearly getline for C strings
  • http://www.cplusplus.com/reference/string/getline.html -- more than about getline for strings
  • http://www.cppreference.com/cppstring/alphabetize.html -- contains a list of functions for C++ strings
  • http://www.cppreference.com/cppstring/string_constructors.html -- lists the C++ string constructors
  • A Book on C by Al Kelley and Ira Pohl

johnsoncous1959.blogspot.com

Source: https://www.cs.uregina.ca/Links/class-info/330/ParsingLine/parsingline.html

0 Response to "Do I Need to Clear a String Before Using Getline Again"

ارسال یک نظر

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel