libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string Error? - c++

Here is a function I'm writing that receives a string of words separated by spaces and adds each word to an array. I keep getting an error that says "libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string." I can't seem to find what the error is.
void lineParser(string line, string words[])
{
string word = "";
int array_index = 0;
int number_of_words = 1;
int string_index = 0;
while (string_index < line.length())
{
if (line.substr(string_index,1) != " ")
{
int j = string_index;
while (line.substr(j,1) != " ")
{
word += line.substr(j,1);
j++;
}
words[array_index] = word;
array_index++;
word = "";
number_of_words++;
string_index = j;
}
else
{
string_index++;
}
}
}

Your variable j is allowed to increase without bounds checking also. It will eventually excede the length of the string you're using it as an index into (.line.substr(j,1)).
A very bad answer would be to add a space at the end of your string line before searching for ' ' characters. A much better answer is to check j against the length of the string before calling any function which accesses the characters in the string using it as an index.

You've got no array bounds checking when accessing words. If the array passed in doesn't have enough space allocated, you'll run past the end of the array.
As you've pointed out below, that isn't necessarily the problem, but it's impossible to say without seeing the rest of your code (main, for example). It's also really bad code, you should never just assume that you know the length of an array, ever. You're using C++, make use of STL containers. It will save you untold headaches associated with arrays.

Related

How do I properly parse substrings so that they can be effective for my newbie calculator?

Please ELI5 if possible, since i've only been coding for a few days and this is my first program! Below is a portion of my script that is supposed to interpret a single line of input that somebody enters (like "5+5" or something).
I have other operations that I want to add later that are formatted differently, which is why I'm using string instead of a switch function or something.
Anyways.. this isn't working :( So below is my logical process and maybe somebody can point out where I messed up? :)
Thank you in advance!
if (fork.find("+" && "-" && "x" && "/"))
{
size_t pos = fork.find("+" && "-" && "x" && "/"); // Defines a position at the operator symbol
string afterfork = fork.substr(pos + 1); // Cuts a substring at the operator symbol + 1
size_t beforepos = fork.find_first_of(fork); // Defines a position at the beginning of the string
string beforefork = fork.substr(beforepos); // cuts a substring at the begninning of the string
string atfork = fork.substr(pos); // cuts a substring that only has one char (the operator +, -, x, etc)
int x = stoi(beforefork.c_str()); // converts the first substring to an integer
int y = stoi(afterfork.c_str()); // converts the third substring to an integer
string operation = atfork; // converts the middle substring that only has one char to a different name.
return input(x, operation, y); // will send this information to the input function (which will do the math for the calculator).
}
To search the string for one of a list of characters, you can use find_first_of. This function returns npos if it didn't find anything.
const size_t operatorPos = input.find_first_of("+-*/");
if (operatorPos == std::string::npos) {
std::cout << "Couldn't find an operator!\n";
return;
}
To split the string into two sub-strings, you can use substr. To get a character at a position, use operator[].
const std::string left = input.substr(0, operatorPos);
const std::string right = input.substr(operatorPos + 1);
const char operation = input[operatorPos];
To convert a string to an integer, well, there are a lot of options. I'll use std::stoi for this answer. This function throws an exception that we need to catch when it can't convert the string to an integer.
int leftInt;
try {
leftInt = std::stoi(left);
} catch (...) {
std::cout << '"' << left << "\" is not a valid integer!\n";
return;
}
int rightInt;
try {
rightInt = std::stoi(right);
} catch (...) {
std::cout << '"' << right << "\" is not a valid integer!\n";
return;
}
If exceptions are really confusing (it took me ages to get my head around exceptions!) then you can try another function. My favourite (and IMO best) is std::from_chars. Another option is to just not catch the exception.
const int leftInt = std::stoi(left);
const int rightInt = std::stoi(right);
In that case, you won't get a nice error message like "five" is not a valid integer!. You'll get something like:
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: stoi: no conversion
Abort trap: 6
Try running std::stoi("five") and see for yourself!
Please, don't use using namespace std;. Just don't!

Hamming Distance: Incorrect Count

I'm trying to create a function to calculate the Hamming Distance between two strings. When I call this function, it should tell me the number of characters that do not match between the two strings.
My output is not correct. I keep getting random number results. Below is my code:
using namespace std;
// function to calculate Hamming distance
int HammingDistance(char seq1[], char seq2[])
{
int i = 0, count = 0;
while (seq1[i] != ' ')
{
if (seq1[i] != seq2[i])
count++;
i++;
}
return count;
}
int main()
{
char seq1[] = "doga";
char seq2[] = "dogb";
cout << HammingDistance(seq1, seq2) << endl;
return 0;
}
I keep getting random number results in my output, like 99 or 207.
When in this example, I should get 1.
Any help on where I'm going wrong is greatly appreciated! Thank you.
You should test the end of string with \0, not with (space).
Your while should, then, be: while (seq1[i] != '\0')
The condition seq1[i] != ' ' is not a good way of checking whether you have reached the end of the string. Assuming that your strings are null terminated then you could use seq1[i] != '\0' instead.
The reason that you are seeing "random" results is that the loop is not encountering a space within the string and is continuing to read past the end of the strings into other parts of the program's memory. The loop only stops when it encounters a byte of memory that happens to contain the same bits as the representation of ' '.
You should also think about how to handle cases where the two strings are different lengths.

Output partial string of a certain index of an array

C++ newbie here, I'm not sure if my title describes what I am trying to do perfectly, but basically I am trying to output one line of a string array for a certain index of that array.
For example: Say myArray[2] is the 3rd index of a string array, and it holds an entire paragraph, with each sentence separated by a newline character.
contents of myArray[2]: "This is just an example.
This is the 2nd sentence in the paragraph.
This is the 3rd sentence in the paragraph."
I would like to output only the first sentence of the content held in the 3rd index of the string array.
Desired output: This is just an example.
So far I have only been able to output the entire paragraph instead of one sentence, using the basic:
cout << myArray[2] << endl;
But obviously this is not correct. I am assuming the best way to do this is to use the newline character in some way, but I am not sure how to go about that. I was thinking I could maybe copy the array into a new, temporary array which would hold in each index a sentence of the paragraph held in the original array index, but this seems like I am complicating the issue too much.
I have also tried to copy the string array into a vector, but that didn't seem to help my confusion.
You can do something along these lines
size_t end1stSentencePos = myArray[2].find('\n');
std::string firstSentence = end1stSentencePos != std::string::npos?
myArray[2].substr(0,end1stSentencePos) :
myArray[2];
cout << firstSentence << endl;
Here's the reference documentation of std::string::find() and std::string::substr().
Below is a general solution to your problem.
std::string findSentence(
unsigned const stringIndex,
unsigned const sentenceIndex,
std::vector<std::string> const& stringArray,
char const delimiter = '\n')
{
auto result = std::string{ "" };
// If the string index is valid
if(stringIndex < stringArray.size())
{
auto index = unsigned{ 0 };
auto posStart = std::string::size_type{ 0 };
auto posEnd = stringArray[stringIndex].find(delimiter);
// Attempt to find the specified sentence
while((posEnd != std::string::npos) && (index < sentenceIndex))
{
posStart = posEnd + 1;
posEnd = stringArray[stringIndex].find(delimiter, posStart);
index++;
}
// If the sentence was found, retrieve the substring.
if(index == sentenceIndex)
{
result = stringArray[stringIndex].substr(posStart, (posEnd - posStart));
}
}
return result;
}
Where,
stringIndex is the index of the string to search.
sentenceIndex is the index of the sentence to retrieve.
stringArray is your array (I used a vector) that contains all of the strings.
delimiter is the character that specifies the end of a sentence (\n by default).
It is safe in that if an invalid string or sentence index is specified, it returns an empty string.
See a full example here.

C++ output duplicating lines when there is a '\n'

I'm having some trouble with this member function of a class. Basically, it's meant to translate words to a different language while maintaining the same punctuation and spaces. lineToTranslate is an input argument which is an array of words, spaces and punctuation. Each word within this has to be taken out of the line individually and translated using the dict.translate() function. This is working properly.
However, the trouble is that when there is are multiple new lines, the previous line of words are output. Also whitespaces are not fully looked after. When there is more than one space in a sentence, only one space is output. Any idea's on where I might be going wrong? Any help would really be appreciated.
Updated code entered with most errors fixed. The only issue I'm having now is that spaces aren't added as needed between words. Where there are 2 blank spaces in a row, one blank space is being entered but where there is one blank space, none is being entered and the words areoutputlikethis.
int len = strlen(lineToTranslate);
string strComplete = "";
const char *cs;
for (int x = 0; x < len; x++)
{
if (!isspace(lineToTranslate[x]))
{
char temp[MAX_WORD_LEN];
int j = 0;
while(lineToTranslate[x] != ' ' && lineToTranslate[x] != '\t' && lineToTranslate[x] != '\n')
{
temp[j] = lineToTranslate[x];
x++;
j++;
}
temp[j] = '\0';
char returned[MAX_WORD_LEN];
if(temp[0] != '\0')
{
dict.translate(returned, temp);
strComplete = strComplete + returned;
}
}
else
{
strComplete = strComplete + lineToTranslate[x];
x++;
}
}
cs = strComplete.c_str();
strcpy(translatedLine, cs);
When your for loop is iterating for spaces or punctuation which dnt qualify to enter while loop you are still executing strComplete = strComplete + returned; which is appending \0 in the middle without any reason, so you have output string like -- <space>\0<space>\0
Please see Default values in array
So solution is to put strComplete = strComplete + returned; inside the if. Your array is uninitialized when it does not enter if(temp[0] != '\0') so you should not be appending returned.
Next....the two lines below should be out of the for loop, since you want the final result of strComplete to be copied to translatedLine instead of each iteration.
cs = strComplete.c_str();
strcpy(translatedLine, cs);
For whitespace I can say that for the first whitespace, it will check the if condition, then the iteration will terminate and we go back to the for loop, x is incremented and now lineToTranslate[x]=' '. Correct?
Okay so the while loop never runs. If condition
if (temp[0]!='\0')
is satisfied.
So now what does return have in store? It isn't initialised. Ur still appending it.
Maybe I am not much help but this is what I figured out.
Try debugging.

C++ is mixing my strings?

I have this really simple c++ function I wrote myself.
It should just strip the '-' characters out of my string.
Here's the code
char* FastaManager::stripAlignment(char *seq, int seqLength){
char newSeq[seqLength];
int j=0;
for (int i=0; i<seqLength; i++) {
if (seq[i] != '-') {
newSeq[j++]=seq[i];
}
}
char *retSeq = (char*)malloc((--j)*sizeof(char));
for (int i=0; i<j; i++) {
retSeq[i]=newSeq[i];
}
retSeq[j+1]='\0'; //WTF it keeps reading from memory without this
return retSeq;
}
I think that comment speaks for itself.
I don't know why, but when I launch the program and print out the result, I get something like
'stripped_sequence''original_sequence'
However, if I try to debug the code to see if there's anything wrong, the flows goes just right, and ends up returning the correct stripped sequence.
I tried to print out the memory of the two variables, and here are the memory readings
memory for seq: http://i.stack.imgur.com/dHI8k.png
memory for *seq: http://i.stack.imgur.com/UqVkX.png
memory for retSeq: http://i.stack.imgur.com/o9uvI.png
memory for *retSeq: http://i.stack.imgur.com/ioFsu.png
(couldn't include links / pics because of spam filter, sorry)
This is the code I'm using to print out the strings
for (int i=0; i<atoi(argv[2]); i++) {
char *seq;
if (usingStructure) {
seq = fm.generateSequenceWithStructure(structure);
}else{
seq = fm.generateSequenceFromProfile();
}
cout<<">Sequence "<<i+1<<": "<<seq<<endl;
}
Now, I have really no idea about what's going on.
If you can use std::string, simply do this:
std::string FastaManager::stripAlignment(const std::string& str)
{
std::string result(str);
result.erase(std::remove(result.begin(), result.end(), '-'), result.end());
return result;
}
This is called "erase-remove idiom".
This happens because you put the terminating zero of a C string outside the allocated space. You should be allocating one extra character at the end of your string copy, and adding '\0' there. Or better yet, you should use std::string.
char *retSeq = (char*)malloc((j+1)*sizeof(char));
for (int i=0; i<j; i++) {
retSeq[i]=newSeq[i];
}
retSeq[j]='\0';
it keeps reading from memory without this
This is by design: C strings are zero-terminated. '\0' signals to string routines in C that the end of the string has been reached. The same convention holds in C++ when you work with C strings.
Personally, I think you would be best off using std::string unless you have really very good reason otherwise:
std::string FastaManager::stripAlignment(std::string value)
{
value.erase(std::remove(value.begin(), value.end(), value.begin(), '-'), value.end());
return value;
}
When you are using C strings you need to realize that they are null-terminated: C strings reach up to the first null character found. With code you posted you introduced an out of range assignment as you allocated 'j' elements and you assign to retSeq[j + 1] which is two character past the end of the string (surely you mean retSeq[j] = 0; anyway).