Segmentation fault using string pointer - c++

I'm a C++ newbie, I'm trying to put in practice pointers with strings. The program I have made is just to store strings the user types in the command line. But I'm getting segfault, not sure why.
This is the code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
//This code is meant to learn how to use pointers and strings
//Ask the user for who are they in the family and save it in string array!
void print_string (string* Value, int const nSize);
int get_names(string* Family_input);
int main ( int nNumberofArgs, char* pszArgs[])
{
cout << "Tis program stores your family members\n";
cout<< "Type the names and write 0 to exit\n";
string familia_string;
string* familia = &familia_string;
int family_number;
family_number=get_names(familia);
cout << "The family members are: ";
print_string(familia, family_number);
cout << endl;
return 0;
}
int get_names(string* Family_input)
{
int i=0;
string input="";
string old_input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
//cin >> *(Family_input+i);
//input=*(Family_input+i);
cin >> input;
*(Family_input + old_input.length()) = input;
old_input=input;
i++;
}
return i;
}
void print_string (string* Value, int const nSize)
{// I don't want to &psValue to be changed!
for (int i=0; i<nSize; i++)
{
cout << *(Value+i) << " ";
//&psValue++;
}
}
I'm not sure if it's because I'm not taking correctly the size of the string, or I'm not using correctly the pointer or is that I have to allocate memory before using the offset.

As #kleszcz pointed out already, the line
*(Family_input + old_input.length()) = input;
is wrong. You are accessing memory that you are not supposed to.
The easiest fix is to change get_names slightly:
int get_names(string* Family_input)
{
int i=0;
string input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
cin >> input;
*Family_input += input; // Just keep on appending to the input argument.
*Family_input += "\n"; // Add a newline to separate the inputs.
i++;
}
return i;
}
Also change print_string to:
void print_string (string* Value)
{
cout << *Value;
}
Of course, print_string has become so simple, you don't need to have it at all.
You could change get_names to use a reference argument instead of a pointer argument. This is a better practice.
int get_names(string& Family_input)
{
int i=0;
string input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
cin >> input;
Family_input += input; // Just keep on appending to the input argument.
Family_input += "\n"; // Add a newline to separate the inputs.
i++;
}
return i;
}
Then, change the call to get_names. Instead of using
family_number=get_names(familia);
use
family_number=get_names(familia_string);

You get seg fault because you haven't allocate memory for an array of strings.
*(Family_input + old_input.length()) = input;
This is total nonsense. If you'd have an array you increment index only by one not by length of string.

If you want to save different names in different string objects I would suggest:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
void print_string(string** Value, int const nSize);
void get_names(string** Family_input, int count);
int main(int nNumberofArgs, char* pszArgs[]) {
cout << "This program stores your family members\n";
int family_number;
cout << "Types the number of family members";
cin >> family_number;
/*allocate the number of string pointers that you need*/
string** familia = new string*[family_number];
cout << "Type the names\n";
get_names(familia, family_number);
cout << "The family members are: ";
print_string(familia, family_number);
cout << endl;
return 0;
}
void get_names(string** Family_input, int count) {
for(int i = 0 ; i < count; i++){
cout << "type " << i << " member\n";
/*create a string obj in the heap memory*/
string *input = new string ("");
// using that way you get only a single word
cin >> *input;
/*create a string object on the stack and put its pointer in the family_array*/
Family_input[i] = input;
}
}
void print_string(string** Value, int const nSize) {
for (int i = 0; i < nSize; i++) {
cout << *(Value[i]) << " ";
}
}

Related

How to read a text file into parallel arrays

I must have a function that reads card information from a text file
(cards.txt) and insert them to parallel arrays in the main program using a pointer.
I have successfully read the text file, but cannot successfully insert the info to the arrays.
#include <iostream>
#include <stream>
#include <string>
using namespace std;
void readCards();
int main() {
ifstream inputFile;
const int SIZE = 10;
int id[SIZE];
string beybladeName[SIZE];
string productCode[SIZE];
string type[SIZE];
string plusMode[SIZE];
string system[SIZE];
readCards();
return 0;
}
void readCards() {
ifstream inputFile;
const int SIZE = 10;
int id[SIZE];
string beybladeName[SIZE];
string productCode[SIZE];
string type[SIZE];
string plusMode[SIZE];
string system[SIZE];
int i = 0;
inputFile.open("cards.txt");
cout << "Reading all cards information..." << endl;
if (inputFile) {
while (inputFile >> id[i] >> beybladeName[i] >> productCode[i] >> type[i] >> plusMode[I] >>
system[I]) {
i++;
}
cout << "All cards information read." << endl;
}
inputFile.close();
for (int index = 0; index < SIZE; index++) {
cout << "#:" << id[index] << endl;
cout << "Beyblade Name: " << beybladeName[index] << endl;
cout << "Product Code: " << productCode[index] << endl;
cout << "Type: " << type[index] << endl;
cout << "Plus Mode: " << plusMode[index] << endl;
cout << "System: " << system[index] << endl;
cout << " " << endl;
}
}
The main problem is that you have two sets of arrays, one in main, and one in readCards. You need one set of arrays in main and to pass those arrays (using pointers) to readCards. Like this
void readCards(int* id, string* beybladeName, string* productCode, string* type, string* plusMode, string* system);
int main()
{
ifstream inputFile;
const int SIZE = 10;
int id[SIZE];
string beybladeName[SIZE];
string productCode[SIZE];
string type[SIZE];
string plusMode [SIZE];
string system [SIZE];
readCards(id, beybladeName, productCode, type, plusMode, system);
return 0;
}
void readCards(int* id, string* beybladeName, string* productCode, string* type, string* plusMode, string* system)
{
...
}

My Ifstream reference is not working although it did in similar previous function

I have a file I want to continue calling on in different functions in my program. It worked fine as a reference in the shiftText function but when I repeated the reference in the next function, all that returns is 0,
Can I get a small hint at something I am missing perhaps to make it behave this way? Thanks!
(PS there's definitely a lot of 'fat' in this that I have included for testing purposes only)
I will eventually return the value of "e" into the shiftText function if you were curious why that's there :)
#include <iostream>
#include <cmath>
#include <fstream>
#include <cctype>
#include <string>
using namespace std;
void inputfile(ifstream &masterfile) // ask for file name
{
string filename;
cout << "Please enter the name and extension of your file " << endl;
cin >> filename;
masterfile.open(filename);
if (!masterfile)
{
cout << "warning: cannot open file" << endl;
exit(1);
}
}
int findShift(ifstream &file, int counter[]) // find most used char
{
char ch;
int code;
while (file.get(ch))
{
code = static_cast<int>(ch);
cout << code << " ";
counter[code]++;
}
int max, min;
int indexMax, indexMin;
max = counter[65];
indexMax = 65;
min = counter[65];
indexMin = 65;
for (int i = 66; i <= 122; i++)
{
if (counter[i] > max)
{
max = counter[i];
indexMax = i;
}
if (counter[i] < min)
{
min = counter[i];
indexMin = i;
}
}
cout << endl
<< "Most frequent was " << indexMax;
return indexMax;
}
void shiftText(ifstream &file) // this is where my program skips over my ifstream reference
{
char ch;
int code;
while (file.get(ch))
{
code = static_cast<int>(ch);
cout << code << " ";
}
}
char stopFlashing() // for sanity
{
char reply;
cout << endl
<< "Press q (or any other key) followed by 'Enter' to quit: ";
cin >> reply;
return 0;
}
int main()
{
int counter[256] = {0};
ifstream file;
inputfile(file);
int e = findShift(file, counter);
shiftText(file);
cout << endl << " " << file << " " << endl; // for testing, a zero is returned
stopFlashing();
}
In function findShift you loop over the file. In function shiftText you are trying to do the same. However, the file is already at its end. Before calling shiftText you should rewind the file by using seekg:
file.seekg(0, std::ios_base::beg)

c++ problem with reverse and count string

I'm just learning c++. I have a problem with my program. I have to write a program which reverse string and count amount word in the string. My program doesn't return amount words and reverse only last word in string. I totally don't know how to correct it. :D
#include <iostream>
using namespace std;
void reverseString(string str)
{
for (int i=str.length()-1; i>=0; i--)
{
cout << str[i];
}
}
void countString(string strg)
{
int word = 1;
for(int j = 0; strg[j] != '\0'; j++)
{
if (strg[j] == ' ')
{
word++;
}
}
}
int main(void)
{
string inputString;
cout << "Give a string: ";
cin >> inputString;
cout << "Reverse string: ";
reverseString(inputString);
cout << "\nCounts words in a string: ";
countString(inputString);
return 0;
}
If you want to read multiple words then you must use getline as >> reads only a single word.
string inputString;
cout << "Give a string: ";
getline(cin, inputString);
To return something from a function you must 1) specify the return type and 2) use a return statement to return a value and 3) do something with that return value in the calling function
Step 1
int countString(string strg) // here we say countString returns an integer
{
...
}
Step 2
int countString(string strg)
{
...
return words; // here we say the value we want to return
}
Step 3
// here we output the value returned from the function
cout << "\nCounts words in a string: " << countString(inputString) << "\n";
Knowing how to write functions that return values is absolutely fundamental C++. You should practise this. See if you can do the same with your reverseString function, instead of printing a string make it return a string.
There are some mistake in your code.In countString() function you return nothing.So it does not print anything.If you take input as a string include a space character,please use getline(cin, inputString).Here the code for you:
#include <iostream>
using namespace std;
void reverseString(string str)
{
for (int i=str.length()-1; i>=0; i--)
{
cout << str[i];
}
}
int countString(string strg)
{
int word = 0;
for(int j = 0; strg[j] != '\0'; j++)
{
word++;
}
return word;
}
int main(void)
{
string inputString;
cout << "Give a string: ";
getline(cin, inputString);
cout << "Reverse string: ";
reverseString(inputString);
cout << "\nCounts words in a string: ";
cout<<countString(inputString)<<endl;
return 0;
}

Reading from a text file into an array

I'm just a beginner for C++
I want to read the text file (maximum of 1024 words) into an array, and I need to ignore all single character words. Can you guys help me to discard words that are single characters to avoid symbols, special characters.
This is my code:
#include <fstream>
#include <string>
#include <iostream>
using namespace std;
const int SIZE = 1024;
void showArray(string names[], int SIZE){
cout << "Unsorted words: " << endl;
for (int i = 0; i < SIZE; i++){
cout << names[i] << " ";
cout << endl;
}
cout << endl;
}
int main()
{
int count = 0;
string names[SIZE];
// Ask the user to input the file name
cout << "Please enter the file name: ";
string fileName;
getline(cin, fileName);
ifstream inputFile;
inputFile.open(fileName);
// If the file name cannot open
if (!inputFile){
cout << "ERROR opening file!" << endl;
exit(1);
}
// sort the text file into array
while (count < SIZE)
{
inputFile >> names[count];
if (names[count].length() == 1);
else
{
count++;
}
}
showArray(names, SIZE); // This function will show the array on screen
system("PAUSE");
return 0;
}
If you change names into a std::vector, then you can populate it using push_back. You could fill names like this.
for (count = 0; count < SIZE; count++)
{
std::string next;
inputFile >> next;
if (next.length() > 1);
{
names.push_back(next);
}
}
Alternatively you could fill all the words into names and then utilize the Erase–remove idiom.
std::copy(std::istream_iterator<std::string>(inputFile),
std::istream_iterator<std::string>(),
std::back_inserter<std::vector<std::string>>(names));
names.erase(std::remove(names.begin(), names.end(),
[](const std::string& x){return x.length() == 1;}), names.end());

Comparing two arrays of strings c++

Ok thank you everyone for your comments. I have fixed much of it. Now when I compile it, it gives me an error on line in main where I call getPercent() saying this :
error: cannot convert ‘std::string’ to ‘std::string*’ for argument ‘3’
to ‘void getPercent(int, std::string*, std::string*, std::string*)’
What can fix this?
#include <iostream>
#include <string>
using namespace std;
string getYours()
{
cout << "Enter your DNA sequence: " ;
string sequence;
cin >> sequence;
return sequence;
}
int getNumber()
{
cout << "Enter the number of potential relatives: ";
int number;
cin >> number;
cout << endl;
return number;
}
void getNames(int number, string name[])
{
for (int i = 0; i < number; i++)
{
cout << "Please enter the name of relative #" << i + 1 << ": ";
cin >> name[i];
}
}
void getSequences(int number, string name[], string newsequence[])
{
cout << endl;
for (int i = 0; i < number; i++)
{
cout << "Please enter the DNA sequence for " << name[i] << ": ";
cin >> newsequence[i];
}
}
void getPercent(int number, string name[], string sequence[],
string newsequence[])
{
cout << endl;
int count = 0;
for (int i = 0; i < number; i++)
{
if (sequence[i] == newsequence[i])
count = count + 10;
cout << "Percent match for " << name[i] << ": " << count << "%";
}
}
int main()
{
string sequence = getYours();
int number = getNumber();
string name[50];
string newsequence[50];
getNames(number, name);
getSequences(number, name, newsequence);
getPercent(number, name, sequence, newsequence);
return 0;
}
A few problems:
getYours() has no side effects. You probably meant to assign to the string sequence in main(), but instead are assigning to a local variable that will be destroyed as it goes out of scope.
No error checking for too many elements in your arrays (try using a std::vector).
You stop at 10 in getPercent() instead of number elements (if that's what you wanted).
In getPercent(), count is not initialized to 0. Something seems strange about the logic in getPercent(), so I am not exactly sure what you are trying to do.
The arguments sequence and newsequence in getPercent() are actually the same type, and would compile fine.
And probably a few other things I've overlooked.