How to read in a bunch of strings in C++? - c++

I need to read in a bunch of strings without knowing in advance how many are there and print them as they are read. So I decided to use while(!feof(stdin)) as an EOF indicator.Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int main(void)
{
char* str;
std::cout<<"\nEnter strings:";
while(!feof(stdin))
{
std::cin>>str;
std::cout<<"\nThe string you entered is"<<str;
}
return 0;
}
The above code for some reason says segmentation fault after I enter the first string.Can someone suggest a fix for that.

You need to allocate some memory for the string you are reading to go into.
All you have currently is a pointer on the stack to some random memory area, which means that as you read characters they will stomp all over other data, or even memory you aren't allowed to write to - which then causes a segfault.
The problem with trying to allocate some memory is that you don't know how much to allocate until the string is read in... (You could just say "300 chars" and see if it's enough. But if it isn't you have the same problem of data corruption)
Better to use C++ std::string type.

str is a pointer to char. It doesn't point anywhere valid when you try to write there.
Try some form of new in C++, or, better yet since you're coding C++, use std::string.

str is declared as char* str, which means it isn't really a string (just a pointer to it, uninitialized BTW), and doesn't allocate any space for it. That's why it seggfaults. Since you program in c++, you can use
std::string str;
and it will work. Don't forget to #include <string>.

A segmentation fault occurs when an application tries to access a memory location that it isn't allowed. In your case the problem is that you are dereferencing a non-initialized pointer: char* str;
A possible solution would be change the pointer to an array, with a suitable size
Something like this may suffice:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int main(void)
{
char str[20];
cout<<"\nEnter strings:";
while(!feof(stdin))
{
cin.width(20); //set a limit
cin>>str;
cout<<"\nThe string you entered is"<<str;
}
return 0;
}

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int main(void)
{
std::string str[300];
std::cout<<"\nEnter strings:";
while(!std::cin.eof())
{
std::cin>>str;
std::cout<<"\nThe string you entered is"<<str;
}
return 0;
}
Should do the trick

Related

c++: problem while copying string into character array

I am trying to copy contents of a file into fields in a class courseInfo.
this is the code im using:
#include<iostream>
#include<fstream>
#include<vector>
#include<sstream>
#include <bits/stdc++.h>
using namespace std;
class courseInfo
{
public:
char courseCode[8];
char courseName[80];
int ECTS;
};
int main()
{
ifstream fin("courses.txt");
if(!fin.is_open())
{
cout<<"file doesn't exist";
return 0;
}
string line;
vector<courseInfo> courses;
while(getline(fin,line))
{
stringstream linestream(line);
string segment;
vector<string> segmentlist;
while(getline(linestream, segment, ';'))
{
segmentlist.push_back(segment);
}
//cout<<segmentlist.at(0).c_str();
courseInfo c;
//segmentlist.at(0).copy(c.courseCode, segmentlist.at(0).size()+1);
//c.courseCode[segmentlist.at(0).size()] = '\0';
strcpy(c.courseCode, segmentlist.at(0).c_str());
cout<<c.courseCode<<"\n;
strcpy(c.courseName, segmentlist.at(1).c_str());
cout<<c.courseCode;
}
return 0;
}
content of courses.txt file:
TURK 101;Turkish l;3.
output i get:
TURK 101
TURK 101Turkish l
the contents of courseCode changes when i copy something into courseName.
why does this happen?
how do i rectify this?
Note how TURK 101 is exactly 8 bytes.
When you cout << c.courseCode, your program prints characters until it encounters a NUL byte. By accident, the first byte of c.courseName is NUL.
After you read into it, it is no longer NUL and thus printing c.courseCode happily continues into c.courseName.
Some options:
The most obvious (and recommended) solution is to use std::string in your struct instead of fixed-size char arrays.
However, this looks like a homework question, so you probably are not allowed to use std::string.
Use std::vector<char> instead, but that is probably also not allowed.
Make courseCode large enough to contain any possible course code, plus one character for the NUL-terminator. In this case, make courseCode 9 chars large.
Use heap-allocated memory (new char[str.size()+1] to allocate a char *, delete[] ptr to free it afterwards). And then change courseInfo to take regular pointers. Ideally all the memory management is done in constructors/destructors. See the rule of three/five/zero.

scanf function for strings

The problem is simple, the code below does not work. it says Process finished with exit code -1073740940 (0xC0000374). Removing ampersand does not change anything.
int main(){
string x;
scanf("%s",&x);
cout << x;
}
scanf() with the %s format specifier reads bytes into a preallocated character array (char[]), to which you pass a pointer.
Your s is not a character array. It is a std::string, a complex object.
A std::string* is not in any way the same as a char*. Your code overwrites the memory of parts of a complex object in unpredictable ways, so you end up with a crash.
Your compiler should have warned about this, since it knows that a char* is not a std::string*, and because compilers are clever and can detect mistakes like this despite the type-unsafe nature of C library functions.
Even if this were valid via some magic compatibility layer, the string is empty.
Use I/O streams instead.
You cannot pass complex objects through the ... operator of printf/scanf. Many compilers print a warning for that.
scanf requires a pointer of type char* pointing to sufficient storage for an argument of %s. std::string is something completely different.
In C++ the iostream operators are intended for text input and output.
cin >> x;
will do the job.
You should not use scanf in C++. There are many pitfalls, you found one of them.
Another pitfall: %s at scanf is almost always undefined behavior unless you you really ensure that the source stream can only contain strings of limited size. In this case a buffer of char buffer[size]; is the right target.
In any other case you should at least restrict the size of the string to scan. E.g. use %20s and of course a matching char buffer, char buffer[21];in this case. Note the size +1.
You should use cin. But if you want to use scanf() for whatever reason and still manipulate your strings with std::string, then you can read the C-string and use it to initialize your C++ string.
#include <iostream>
#include <cstdio>
#include <string>
using std::cout;
using std::string;
int main()
{
char c_str[80];
scanf("%s", c_str);
string str(c_str);
cout << str << "\n";
}
If you want to use strings, use cin (or getline).
string s;
cin>>s; //s is now read
If you want to use scanf, you want to have a char array (and don't use &):
char text[30];
scanf("%s", text); //text is now read
You can use char[] instead of string
include <iostream>
using namespace std;
int main()
{
char tmp[101];
scanf("%100s", tmp);
cout << tmp;
}

Program crashes when using string instead of char array

I was trying to write a program to enter texts like passwords (display "*" instead of the character which in input by the user).
The problem is, when I use char arrays to store the password, the program works fine, but when I use a string class variable for the same purpose, my program crashes while displaying the string.
Here is the code:
// *********THIS CODE WORKS FINE***********
#include <iostream>
#include<string>
#include<conio.h>
int main()
{
using namespace std;
int i=0;
cout<<"Enter a password,press ENTER to finish writing"<<endl;
char passw[20];
passw[i]=getch();
while(passw[i]!=13)
{
i++;
cout<<"*";
passw[i]=getch();
}
passw[i+1]='\0';
cout<<"\nPassword is "<<passw;
return 0;
}
Now when I replace char passw[20] with string passw:
//**********THIS CODE CRASHES!!*********
#include <iostream>
#include<string>
#include<conio.h>
int main()
{
using namespace std;
int i=0;
cout<<"Enter a password,press ENTER to finish writing"<<endl;
string passw;
passw=getch();
while(passw[i]!=13)
{
i++;
cout<<"*";
passw[i]=getch();
}
cout<<"\nPassword is "<<passw;
return 0;
}
Can anybody explain why this is happening?
Just started with strings and there's just too much for me to know about strings :)
In string you can use string concatenation.
you can save your char and add it to your string variable.
char ch;
string pass;
ch=getch();
pass=pass+ch;
You're accessing a location (passw[i]) that is not yet existing in your std::string and you're not storing it correctly to a string. You should use the method passwd.push_back(char) to store it.
Check for reference: http://en.cppreference.com/w/cpp/string/basic_string/push_back
A string works differently compared to a char array. You probably know that char passw[20] in your first example creates an array with space for up to 20 chars. These can then be accessed using operator[] without a problem. A string, unlike a basic array, is a dynamic data structure, meaning it grows and shrinks over time as your program runs. Its content can also be accessed using operator[], however, this will not append to the string, it can only be used to change what is already there.
It's important to note that in c++, not all operations will perform what is known as bounds checking. In your second example, you access the i-th character of your string and write a character to that location. However, what would happen if you try to write, for instance, to the 10-th character of a string that only has space for 5? When doing so via operator[], the program will write to whatever location the 10-th character would be at, even though that part of memory is actually not part of the string. Anything could be there and will be overwritten by that operation. As you can probably imagine, this is not desirable at all and can lead to all sorts of problems later down the line. If you're lucky, your program will crash immediately on the write. It did not in your case, however, that's not a good thing; writing out of bounds can cause a heap corruption (the heap being a certain part of memory) which generally leads to a crash at some point down the line.
It's fine to use operator[] to change a strings characters if and only if you know whatever index you're accessing is within the strings size. Otherwise, you need to append to the string using an appropriate member function. These will enlarge the string if necessary.
You always need to pay attention when working with dynamic memory and what parts of it you're accessing (in your first example, for instance, you would also write out of bounds if your password is too long).

Able to Access Elements with Index Greater than Array Length

The following code seems to be running when it shouldn't. In this example:
#include <iostream>
using namespace std;
int main()
{
char data[1];
cout<<"Enter data: ";
cin>>data;
cout<<data[2]<<endl;
}
Entering a string with a length greater than 1 (e.g., "Hello"), will produce output as if the array were large enough to hold it (e.g., "l"). Should this not be throwing an error when it tried to store a value that was longer than the array or when it tried to retrieve a value with an index greater than the array length?
The following code seems to be running when it shouldn't.
It is not about "should" or "shouldn't". It is about "may" or "may not".
That is, your program may run, or it may not.
It is because your program invokes undefined behavior. Accessing an array element beyond the array-length invokes undefined behavior which means anything could happen.
The proper way to write your code is to use std::string as:
#include <iostream>
#include <string>
//using namespace std; DONT WRITE THIS HERE
int main()
{
std::string data;
std::cout<<"Enter data: ";
std::cin>>data; //read the entire input string, no matter how long it is!
std::cout<<data<<std::endl; //print the entire string
if ( data.size() > 2 ) //check if data has atleast 3 characters
{
std::cout << data[2] << std::endl; //print 3rd character
}
}
It can crash under different parameters in compilation or compiled on other machine, because running of that code giving undefined result according to documentaton.
It is not safe to be doing this. What it is doing is writing over the memory that happens to lie after the buffer. Afterwards, it is then reading it back out to you.
This is only working because your cin and cout operations don't say: This is a pointer to one char, I will only write one char. Instead it says: enough space is allocated for me to write to. The cin and cout operations keep reading data until they hit the null terminator \0.
To fix this, you can replace this with:
std::string data;
C++ will let you make big memory mistakes.
Some 'rules' that will save you most of the time:
1:Don't use char[]. Instead use string.
2:Don't use pointers to pass or return argument. Pass by reference, return by value.
3:Don't use arrays (e.g. int[]). Use vectors. You still have to check your own bounds.
With just those three you'll be writing some-what "safe" code and non-C-like code.

Segmentation fault while using "ifstream"

I'm trying to get a part of text in a file.
I used "ifstream":
#include <fstream>
void func(){
char *myString;
ifstream infile;
infile.open("/proc/cpuinfo");
while (infile >> myString){
if (!strcmp(myString,"MHz"))
break;
}
}
and I get a "Segmentation fault". does anyone know why?
You have not allocated memory for the myString. Use std::string. Or better any other language, python, perl, or unix utils such as grep, awk, sed.
Because the target value should be:
std::string myString;
and not char*. It's possible to use char*, but you have to ensure that it points to something big enough first. (In your case, it doesn't point anywhere—you forgot to initialize it.) And defining “big enough” is non-trivial, given that you don't know the size of the next word until you've read it.
There's a reason why C++ has a string class, you know. It's because using char pointers is cumbersome and error-prone.
infile >> myString
will read from the file into *wherever myString points to. And it is an uninitialized pointer, it points to some random garbage address.
If you absolutely do want to use char pointers instead of strings, you'll have to allocate a buffer you can read data into.
But the sane solution is to replace it entirely by std::string.
Because you did not allocate memory for myString. The quick solution to this is to use std::string instead of the C-style char* strings, which does memory management so you don't have to.
Here's why your error occurs:
When you declare char *myString you are creating a pointer to a character. However you do not initialize this pointer to anything, so it can point absolutely anywhere in memory. When you do infile >> myString you are going to write a bunch of characters at an unspecified location in memory. It just so happens that this location was a vital part of your program, which caused it to crash.
char myString[256] compiles fine just as well too.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void func()
{
char myString[256] ;
ifstream infile;
infile.open("/proc/cpuinfo");
while ( ! infile.eof() )
{
infile >> myString;
cout<<myString<<" \n";
if (! strcmp(myString,"MHz") )
{
infile.close();
break;
}
}
infile.close();
cout<<" \n";
}
int main()
{
func();
return 0;
}