My friend is writing a text-based game and asked me to look at this code that was crashing. I debugged it and it was getting a seg fault when creating a dynamic array. I'm not sure exactly why, I recommended he just avoid pointers altogether and use a vector so hopefully that will solve his problem but I'm curious as to what exactly is going wrong here. Here's his code:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
class nation
{
public:
void init();
string genName();
string getName();
private:
string myName;
int* myBorderPoints;
};
string nation::getName()
{
return myName;
}
string nation::genName()
{
int listLength = 0, listPos = 0, listRand = 0;
string nameToGen = "";
string* namePartList;
ifstream fileName;
fileName.open("NamePart1.txt");
listLength = fileName.tellg();
namePartList = new string[listLength]; // Seg fault here
while (fileName.good())
{
while (!fileName.eof())
{
getline(fileName,namePartList[listPos]);
listPos += 1;
}
}
listRand = rand() % listLength;
nameToGen += namePartList[listRand];
fileName.close();
listLength = 0;
listPos = 0;
listRand = 0;
nameToGen = "";
fileName.open("NamePart2.txt");
listLength = fileName.tellg();
namePartList = new string[listLength];
while (fileName.good())
{
while (!fileName.eof())
{
getline(fileName,namePartList[listPos]);
listPos += 1;
}
}
listRand = rand() % listLength;
nameToGen += namePartList[listRand];
fileName.close();
return nameToGen;
}
void nation::init()
{
srand(time(NULL));
myName = genName();
}
int main()
{
nation testNation;
testNation.init();
cout << testNation.getName();
return 0;
}
You are calling tellg:
listLength = fileName.tellg();
without having read anything, which depending on whether the file was opening successfully or not will return 0 or -1 and so you will have this called:
namePartList = new string[listLength]
with a probably a undesirable value. I am pretty sure it is returning -1 since allocating a zero sized should be ok.
This also applies later on the code as well, going with std::vector probably makes more sense.
Related
I am trying to use pointer in reading string array,but it occurs an exception.
Here is the code:
#include<vector>
#include<string>
#include<iostream>
using namespace std;
int countn = 1;
class Solution {
public:
string findPrefix(string compa, string& compb,int n) {
string prefixi;
for (int i = 0; i < compa.length(); i++) {
if (compa[i] == compb[i]) {//Exception occurs here
prefixi.push_back(compa[i]);
}
else break;
}
countn++;
string* nxt = &compb;
nxt++;
if (countn<=n) {
prefixi = findPrefix(prefixi,*nxt,n);
}
return prefixi;
}
string longestCommonPrefix(vector<string>& strs) {
int n = strs.size();
string prefix;
prefix = findPrefix(strs[0], strs[countn],n);
return prefix;
}
};
int main() {
vector<string> str = { "flower", "fly","flip"};
Solution test;
string ans = test.longestCommonPrefix(str);
cout << ans << endl;
}
Exception occurs in line13
Then I checked the auto box and to find that the pointer nxt is pointing to the last string in str vector(string"filp"), I wonder if the pointer is out of boundary, but I do not know how to fix it and make my code work. Help me plz.
im currently setting up the highscore-part for a game and I have a very weird problem because of the weird behaviour of the std::sort function.
Im doing the whole thing in RAD Studio 10.2 (Embarcadero IDE) in C++.
So he is my code:
std::string Line;
int count = 0;
int i = 0;
ifstream File("Highscore.txt");
if(File.is_open())
{
while(getline(File, Line))
{
count += 1;
}
File.close();
}
ifstream ReadFile("Highscore.txt");
if(ReadFile.is_open())
{
string *scores = NULL;
scores = new string[count];
while(getline(ReadFile, Line))
{
scores[i] = Line;
i += 1;
}
ReadFile.close();
std::sort(scores, (scores+count));
UnicodeString Uscores1 = scores[0].c_str();
UnicodeString Uscores2 = scores[1].c_str();
UnicodeString Uscores3 = scores[2].c_str();
UnicodeString Uscores4 = scores[3].c_str();
UnicodeString Uscores5 = scores[4].c_str();
LScore1->Caption = Uscores1;
LScore2->Caption = Uscores2;
LScore3->Caption = Uscores3;
LScore4->Caption = Uscores4;
LScore5->Caption = Uscores5;
}
I get no errors from the compiler/linker and everything work should fine.
The string array gets filled correctly and so on.
But its not sorting.
To show the problem to you I made a screenshot - on the left you can see the txtfile with the scores; on the right you can see the output after the sorting algorithm:
My question now is why this is happening?
Thanks for you help
Welcome to C++. Since you want to list numbers by rank, read them as int not string. Forget about operator new. You will not need it for years, if ever. Use standard containers like std::vector, which take care of the memory allocation and de-allocation transparently.
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
int main() {
using namespace std;
vector<int> scores;
{
ifstream inp("Highscore.txt");
int next;
while (inp >> next) {
scores.push_back(next);
}
}
sort(scores.begin(), scores.end());
for (auto s : scores) {
cout << s << '\n';
}
return 0;
}
How about something like:
int i = 0;
int * scoresInteger = NULL;
scoresInteger = new int[count];
for(i = 0; i < count; i++)
{
scoresInteger[i] = std::stoi(scores[i]);
}
std::sort(scoresInteger, scoresInteger + count);
If you need to, you can convert the integers back into strings using targetStrings[i] = std::to_string(scoresInteger[i]).
string * targetScores = NULL;
targetScores = new std::string[count];
for(i = 0; i < count; i++)
{
targetScores[i] = std::to_string(scoresInteger[i]);
}
delete [] scoresInteger;
scoresInteger = NULL;
Don't forget to delete [] targetScores later.
My question now is why this is happening?
Because your scores are compared as strings and not as ints. Because of that "3" is greater that "25"
std::cout << std::boolalpha << (std::string("3") > std::string("25")) << std::endl; // true
Luckily you can pass a custom comparator (or lambda) to the std::sort to make it behave just as you want:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
const int count = 5;
std::string scores[count] = { "35","25","3","4","5" };
// TWEAKED SORT
std::sort(scores, scores + count, [](std::string const &s1, std::string const &s2)
{
return std::stoi(s2) < std::stoi(s1);
});
// TEST
for (auto const &s : scores)
{
std::cout << s << std::endl;
}
}
The compared strings in the above example are converted to ints and then compared, resulting in the desired sorting order.
35
25
5
4
3
Please note that I do not agree with the rest of your code and I think you should rethink the implementation, as it would be much easier, safer and more efficient to use std::vector<std::string> for your task.
I am having trouble with my method. I want it to accept an array of strings as its first argument instead of a vector string. However when I try to use an Array of strings and make one in the main function I get all kinds of errors. I don't know if I should user a pointer to an array of strings for my argument or just a string. Any help?
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
#include<iostream>
using namespace std;
class UserName
{
public:
string newMember(string* exist, string newname) {
bool found = false;
bool match = false;
stringstream ss;
string result;
string othername;
for(int i = 0; i < exist.size(); i++){
if(exist[i] == newname){
found = true;
break;
}
}
if(found){
for(int x = 1; ; x++){
match = false;
ss.str("");
ss << newname << x;
for(int i = 0; i < exist.size();i++){
//cout << ss.str() << endl;
othername = ss.str();
if(exist[i] == othername){
match = true;
break;
}
}
if(!match){
result = ss.str();
break;
}
}
return result;
}
else return newname;
}
};
int main(){
UserName u;
string Database [4];
Database[0] == "Justin";
Database[1] == "Justin1";
Database[2] == "Justin2";
Database[3] == "Justin3";
cout << u.newMember(Database, "Justin") << endl;
return 0;
}
Arrays in C++ are unfortunately a special case, and in many ways do not behave like proper values. A few examples:
void foo(int c[10]); // looks like we're taking an array by value.
// Wrong, the parameter type is 'adjusted' to be int*
int bar[3] = {1,2};
foo(bar); // compile error due to wrong types (int[3] vs. int[10])?
// No, compiles fine but you'll probably get undefined behavior at runtime
// if you want type checking, you can pass arrays by reference (or just use std::array):
void foo2(int (&c)[10]); // paramater type isn't 'adjusted'
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10]
int baz()[10]; // returning an array by value?
// No, return types are prohibited from being an array.
int g[2] = {1,2};
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax
h = g; // copying an array? No, assigning to arrays is prohibited
(taken from here)
If you want an array that behaves like a proper value use std::array.
#include <array>
#include <string>
void foo(std::array<std::string, 10> arr) { /* ... */ }
int main() {
std::array<std::string, 10> arr = {"Justin", "Justin1", "Justin2", "Justin3"};
foo(arr);
}
Use like following:
std::string Database[] ={ "Justin", "Justin1", "Justin2","Justin3" };
newmember as
string newMember(std::string exist[], std::size_t n, string newname)
replace exist.size() with n
In main :
cout << u.newMember(Database, 4,"Justin") << endl;
Also as per your edited post
The operator = is not the same as the operator ==, the first one is an assignment operator (assigns the value at its right to the variable at its left) and the other one == is the equality operator
So you need to use as:
Database[0] = "Justin";
Database[1] = "Justin1";
Database[2] = "Justin2";
Database[3] = "Justin3";
Im trying to write a powerset to a file, but I get a heap corruption if my starting array is bigger than size 6, and im not sure why. It works fine with any size of array 6 or under. Cant figure this out.
Also, test.txt is where I read in the array. If the file contains"1,2,3,4,5,6" it works fine, but it it contains "1,2,3,4,5,6,7" I get heap corruption.
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include "N26.h"
#include <math.h>
using namespace std;
void increaseArray(int* theArray, int size)
{
int i = size;
int n = i+1;
int* newArray = new int[n];
for(int cnt=0;cnt<n;cnt++)
{
newArray[cnt] = theArray[cnt];
}
newArray[n-1]= NULL;
theArray = newArray;
return;
}
void printPowerSet(int *s, int n)
{
int i=0,j=0;
ofstream myFile;
double SetSize=pow(2.0,n);
myFile.open("powerset1.txt", std::ios_base::app);
cout<<"{size of original}"<< n <<endl;
cout<<"{number of sets}"<< SetSize-1 <<endl;
for(i=1;i<SetSize;++i)
{
for(j=0;j<n;++j)
{
if(((i>>j)&1)==1)
{
myFile << s[j] <<",";
}
}
myFile<<endl;
}
return;
}
int main()
{
ifstream myFile;
int item;
string input ="";
string fileName = "test.txt";
myFile.open(fileName);
while(myFile)
{
int k = 1;
int* transaction= new int[1];
if(!getline(myFile,input))
break;
istringstream ss(input);
while(ss)
{
if(!getline(ss,input, ','))
break;
input.erase(remove_if(input.begin(), input.end(), isspace), input.end());
item = atoi(input.c_str());
transaction[k-1] = item;
increaseArray(transaction,k);
k++;
}
for(int i =0; i<k-1;i++)
{
cout << transaction[i];
}
printPowerSet(transaction, k-1);
cout << endl;
transaction=NULL;
}
system("Pause");
return 0;
}
Your increaseArray() function doesn't work because you're only changing a local copy of the pointer. You'd have to pass a double pointer or a pointer reference to do what you want.
Example of a reference to pointer:
void increaseArray(int*& theArray, int size)
Instead, I'd recommend using a std::vector, since this will grow automatically.
I doubt this has any bearing on your problem, but I don't see that you ever delete, either. You are leaking memory. Before reassigning your pointer with a new allocation, delete the old allocation:
delete [] theArray; // The "[]" is important!
theArray = newArray;
In addition to Fred's answer.
Look at what's going on inside increaseArray(), specifically these lines:
int i = size;
int n = i+1;
int* newArray = new int[n];
for(int cnt=0;cnt<n;cnt++)
{
newArray[cnt] = theArray[cnt];
}
You allocate an array of size + 1 elements, and then iterate over the original. That's off-by-one, i.e. you are accessing one element outside of the original array. That might get you a segmentation fault depending on how new lays out the heap, but sure is undefined behavior.
I am new to C++ programming and am obviously missing something. In the following code the compiler doesn't seem to recognize this line: lengths[counter] = findDups(crtLine); I get an error: variable "lengths" set but not used. I cannot figure out why it is not recognizing this line, when the names[counter] = getNameOnly(crtLine) works perfectly and it is essentially the same format. Any insight into this issue is appreciated!
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
string getNameOnly (string line) {
return line.substr(0, line.find(' '));
}
int findDups (string line) {
string lnCpy = line;
sort(lnCpy.begin(), lnCpy.end());
int i = 0;
int dups = 0;
int j = 1;
int len = lnCpy.length();
while (j < len) {
if (lnCpy.at(i) == lnCpy.at(j))
dups++;
i++;
j++;
}
if (dups != 0)
return 0;
else
return lnCpy.length();
}
int main() {
string names[1219];
int lengths[1219];
string crtLine;
int counter = 0;
ifstream myfile ("dist.male.first");
if (myfile.is_open()) {
while (!myfile.eof()) {
getline(myfile,crtLine);
lengths[counter] = findDups(crtLine);
names[counter] = getNameOnly(crtLine);
counter++;
}
myfile.close();
}
else cout << "Unable to open file";
return (0);
}
That's a warning, not an error, and it tells you exactly what the problem is: you put things into the variable named lengths, but never check what's in it, you might as well never store anything there in the first place.
You don't get a similar warning for names, because the assignment operator of std::string has side effects, and the compiler assumes you were interested in the side effect (rather than getting the value out later).