Segmentation fault std::vector<std::string> - c++

I write a function to return a vector and call it in other functions, in some function, it runs well, but in some, it throws the Segmentation fault.
This is my functionA, it returns a vector
std::vector<std::string> functionA(std::vector<std::string> l){
...
char *list_inorder;
int nnn = sprintf(list_inorder,"%-5d%-35s%-20s%-8s\n",(i),(s.at(1)).c_str(),(s.at(2)).c_str(), (s.at(0)).c_str());
...
}
return result;
}
This is how I call it in other function, I use the same method to call it but some can work some cannot.
std::vector<std::string> vectorA=functionA(vectorB);

You never point list_inorder to anything before you sprintf to it.
That means undefined behavior. Intermittent crashes are expected from undefined behavior.
Since you are using streams everywhere else, why not a stream for the output instead of sprintf? from memory ostringstream, but google will give a better answer than my memory...
A simple fix would be to change char *list_inorder; to char list_inorder[50]; (assumes 50 chars is enough to fit your string) - this is not ideal and using streams would be better.

Related

String input/output

I am kinda new to programming, so pardon me for any stupid questions :P, i noticed that when i write this
int main()
{
string s;
s[0]='a';
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
The output is 0 a , firstly why is the size 0? and why didn't anything get printed when i write cout<<s; but it gives a for cout<<s[0]. if i use push_back it gives normal out put.
int main()
{
string s;
s.push_back('a');
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
output :- 1a a
I might have overlooked something but i would be really appreciate if some could point out the cause.
Thank you.
EDIT: Such fast replies! thanks for your answers, i couldn't figues out how to reply to comments so edited the question body(first time using stackoverflow),
(any help on this would be appreciated as well), one more thing so when i use cout<<s[0] does it give a because a was stored on the next address of string
s?
and once again thanks for clearing that up!
What you've overlooked is that in C++ strings don't automatically grow when you assign characters to them. So
string s;
s[0]='a';
is an error because the s has size zero so there is no 'room' for the character 'a'. The correct way to add a character to a string is to use push_back which is why your second example works.
Because of the error your first example has what's called undefined behaviour (UB for short). This means the output of your program is not predictable at all, and it's more or less a waste of time asking why it outputs what it does. It could just as easily crash.
This:
string s;
creates a string containing no characters. Then this:
s[0]='a';
attempts to make a change to one of those non-existent characters. The result of this is undefined behaviour - your program goes into an unknown state.
If you would like to make your compiler warn you about this problem, you can use the at() member function of string:
s.at(0) = 'a';
Now your program will throw an std::out_of_range exception when you try to change that non-existant character.
Containers don't automatically allocate storage, so you are writing outside the allocated storage. In other words, that's a bug in your program. One advise: Many C++ implementations have a way to activate diagnostics for debugging programs, those would have caught this error.
when I write this
string s;
s[0]='a';
the output is 0, firstly why is the size 0?
The output is zero because operator[i] assumes that the string has sufficient space to store i+1 characters. In your case, string's size is zero, so accessing element at index 0 is undefined behavior.
and why didn't anything get printed when I write to cout
The same thing reason applies: after undefined behavior the program could output anything, but it happens to output nothing.
int main()
{
string s;
s='a';
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
Just take off [0] after s in initialisation because s is of type string not type char.
Just write s and it will work.

Manipulating std::string

The below code does not give any fault/error/warning(although I think there might be some illegal memory access happening). Strangely, the size of the string being printed using 2 different methods(strlen and std::string.size() is coming out differently.
strlen(l_str.c_str()-> is giving the size as 1500, whereas,
l_str.size()-> is giving the size as 0.
#include <string.h>
#include <string>
#include <stdio.h>
#include<iostream>
using namespace std;
void strRet(void* data)
{
char ar[1500];
memset(ar,0,1500);
for(int i=0;i<1500;i++)
ar[i]='a';
memset(data,0,1500); // This might not be correct but it works fine
memcpy(data,ar,1500);
}
int main()
{
std::string l_str;
cout<<endl<<"size before: "<<l_str.length();
int var=10;
strRet((void *)l_str.c_str());
printf("Str after call: %s\n",l_str.c_str());
cout<<endl<<"size after(using strlen): "<<strlen(l_str.c_str());
cout<<endl<<"Size after(using size function): "<<l_str.size();
printf("var value after call: %d\n",var);
return 0;
}
Please suggest, if I'm doing something which I'm not supposed to do!
Also, I wanted to know which memory bytes are being set to 0 when I do memset(data,0,1500);? What I mean to ask is that if suppose, my string variable's starting address is 100, then does memset command sets the memory range [100,1600] as 0? Or is it setting some other memory range?
memset(data,0,1500); // This might not be correct but it works fine
It isn't correct, and it doesn't "work fine". This is Undefined Behaviour, and you're making the common mistake of assuming that if it compiles, and your computer doesn't instantly catch fire, everything is fine.
It really isn't.
I've done something which I wasn't supposed to do!
Yes, you have. You took a pointer to a std::string, a non-trivial object with its own state and behaviour, asked it for the address of some memory it controls, and cast that to void*.
There's no reason to do that, you should very rarely ever see void* in C++ code, and seeing C-style casts to any type is pretty worrying.
Don't take void* pointers into objects with state and behaviour like std::string until you understand what you're doing and why this is wrong. Then, when that day comes, you still won't do it because you'll know better.
We can look at the first problem in some fine detail, if it helps:
(void *)l_str.c_str()
what does c_str() return? A pointer to some memory owned by l_str
where is this memory? No idea, that's l_str's business. If this standard library implementation uses the small string optimization, it may be inside the l_str object. If not, it may be dynamically allocated.
how much memory is allocated at this location? No idea, that's l_str's business. All we can say for sure is that there is at least one legally-addressable char (l_str.c_str()[0] == '\0') and that it's legal to use the address l_str.c_str()+1 (but only as a one-past-the-end pointer, so you can't dereference it)
So, the statement
strRet((void *)l_str.c_str());
passes strRet a pointer to a location containing one or more addressable chars, of which the first is zero. That's everything we can say about it.
Now let's look again at the problematic line
memset(data,0,1500); // This might not be correct but it works fine
why would we expect there to be 1500 chars at this location? If you'd documented strRet as requiring a buffer of at least 1500 allocated chars, would it look reasonable to actually pass l_str.c_str() when you know l_str has just been default constructed as an empty string? It's not like you asked l_str to allocate that storage for you.
You could start to make this work by giving l_str a chance to allocate the memory you intend to write, by calling
l_str.reserve(1500);
before calling strRet. This still won't notify l_str that you filled it with 'a's though, because you did that by changing the raw memory behind its back.
If you want this to work correctly, you could replace the entirety of strRet with
std::string l_str(1500, 'a');
or, if you want to change an existing string correctly, with
void strRet(std::string& out) {
// this just speeds it up, since we know the size in advance
out.reserve(1500);
// this is in case the string wasn't already empty
out.clear();
// and this actually does the work
std::fill_n(std::back_inserter(out), 1500, 'a');
}

Program creating file path using strdup and strcat crashes when fed more than 39 characters

I am trying to concatenate two char arrays using the function strcat(). However the program crashes.
#include <cstdio>
#include <cstring>
int main() {
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *file_bk_path = strcat(strdup(file_path), ".bk");
printf("%s\n", file_bk_path);
return 0;
}
The strangest thing to me is that the program indeed produces an output before crashing:
D:/MyFolder/YetAnotherFolder/test.txt.bk
What is the reason for this problem and how it can be fixed?
Error state is reproduced in Windows (MinGW 7.2.0).
strdup is creating new memory for you to hold a duplicate of the string. The memory is only as long as strlen(file_path) + 1. You then try to add an extra 2 characters into memory that you don't own. You will go out of range of the memory created and create some undefined behaviour. It might print because setting the memory and printing the first part could be happening correctly, but it is undefined and anything can happen. Also note, in strdup you need to call free on the memory it creates for you, or you are going to leak some memory.
Here is a much simpler way to do this, use a std::string:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
std::string file_bk_path = std::string(file_path) + ".bk";
std::cout << file_bk_path << "\n";
Here is a live example.
If it absolutely needs to be in C-style then you are better off controlling the memory yourself:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *bk_string = ".bk";
char *file_bk_path = malloc((strlen(file_path) + strlen(bk_string) + 1)*sizeof(char));
if (!file_bk_path) { exit(1); }
strcpy(file_bk_path, file_path);
strcat(file_bk_path, bk_string);
printf("%s\n", file_bk_path);
free(file_bk_path);
Here is a live example.
As mentioned in the comments and answers, strdup mallocs the length of your path string, plus an extra cell for the string end character '\0'. When you concatenate to this two characters writing after the allocated area.
Following #Ben's comments, I'd like to elucidate some more:
To be clear strcat adds a delimiter, but this is already after the memory you were allocated.
In general unless you specifically hit no-no addresses, the program will probably run fine - in fact this is a common hard to find bug. If for example you allocate some more memory right after that address, you will be deleting said delimiter (so printing the string will read further into the memory.
So in general, you may be OK crash wise. The crash (probably) occurs when the program ends, and the OS cleans up the memory you forgot to free yourself - That extra cell is a memory leak, and will cause the crash. So you do get a full print, and only after a crash.
Of course all of this is undefined behavior, so may depend on the compiler and OS.

Passing a file pointer to a function

If I pass a FILE pointer to a function, is it updated?
Can I do something like the following?
FILE* fp;
size_t read, len;
char *key;
fp=fopen((tmpDir+"/"+filename).c_str(),"r");
while((read=getline(&key,&len,fp))!=-1){
if (header_section){
processHeader(fp);
}else{
processBody(fp);
}
}
fclose(fp);
void processHeader(FILE* fp){
size_t read, len;
char *key;
while((read=getline(&key,&len,fp))!=-1){
... do header processing ...
if(strcmp(key,"end_of_header")==0){
return;
}
}
}
void processBody(FILE* fp){
size_t read, len;
char *key;
while((read=getline(&key,&len,fp))!=-1){
... process body data ...
}
}
The above code doesn't work (I get a Segmentation Fault). Is there a way to process parts of a text file in different functions according to the section of the file?
Yes, it is possible to pass a FILE * to a function. After all, various standard C I/O functions accept an argument which is a pointer.
However, FILE is an opaque type. Whether the FILE * points at something (e.g a data structure) which is updated is implementation defined. But if your code is doing things that are valid on a FILE * (e.g. passing it to C I/O functions) then that would not explain a segmentation fault.
The partial code you have supplied is not sufficient to identify the cause of your "segmentation fault". Odds are, if the program is crashing, some code in your program is exhibiting undefined behaviour. But the simple act of passing a FILE *, obtained as a return value from fopen(), as an argument to a function would not be the cause. You need to look at other code in your program.
And, in C++, you would be better off using C++ streams than C I/O functions. But, at most, that will only change the symptom. If other code is the cause of your undefined behaviour, changing method of I/O (assuming you do it correctly) won't fix that.

Splitting a std::string into two const char*s resulting in the second const char* overwriting the first

I am taking a line of input which is separated by a space and trying to read the data into two integer variables.
for instance: "0 1" should give child1 == 0, child2 == 1.
The code I'm using is as follows:
int separator = input.find(' ');
const char* child1_str = input.substr(0, separator).c_str(); // Everything is as expected here.
const char* child2_str = input.substr(
separator+1, //Start with the next char after the separator
input.length()-(separator+1) // And work to the end of the input string.
).c_str(); // But now child1_str is showing the same location in memory as child2_str!
int child1 = atoi(child1_str);
int child2 = atoi(child2_str); // and thus are both of these getting assigned the integer '1'.
// do work
What's happening is perplexing me to no end. I'm monitoring the sequence with the Eclipse debugger (gdb). When the function starts, child1_str and child2_str are shown to have different memory locations (as they should). After splitting the string at separator and getting the first value, child1_str holds '0' as expected.
However, the next line, which assigns a value to child2_str not only assigns the correct value to child2_str, but also overwrites child1_str. I don't even mean the character value is overwritten, I mean that the debugger shows child1_str and child2_str to share the same location in memory.
What the what?
1) Yes, I'll be happy to listen to other suggestions to convert a string to an int -- this was how I learned to do it a long time ago, and I've never had a problem with it, so never needed to change, however:
2) Even if there's a better way to perform the conversion, I would still like to know what's going on here! This is my ultimate question. So even if you come up with a better algorithm, the selected answer will be the one that helps me understand why my algorithm fails.
3) Yes, I know that std::string is C++ and const char* is standard C. atoi requires a c string. I'm tagging this as C++ because the input will absolutely be coming as a std::string from the framework I am using.
First, the superior solutions.
In C++11 you can use the newfangled std::stoi function:
int child1 = std::stoi(input.substr(0, separator));
Failing that, you can use boost::lexical_cast:
int child1 = boost::lexical_cast<int>(input.substr(0, separator));
Now, an explanation.
input.substr(0, separator) creates a temporary std::string object that dies at the semicolon. Calling c_str() on that temporary object gives you a pointer that is only valid as long as the temporary lives. This means that, on the next line, the pointer is already invalid. Dereferencing that pointer has undefined behaviour. Then weird things happens, as is often the case with undefined behaviour.
The value returned by c_str() is invalid after the string is destructed. So when you run this line:
const char* child1_str = input.substr(0, separator).c_str();
The substr function returns a temporary string. After the line is run, this temporary string is destructed and the child1_str pointer becomes invalid. Accessing that pointer results in undefined behavior.
What you should do is assign the result of substr to a local std::string variable. Then you can call c_str() on that variable, and the result will be valid until the variable is destructed (at the end of the block).
Others have already pointed out the problem with your current code. Here's how I'd do the conversion:
std::istringstream buffer(input);
buffer >> child1 >> child2;
Much simpler and more straightforward, not to mention considerably more flexible (e.g., it'll continue to work even if the input has a tab or two spaces between the numbers).
input.substr returns a temporary std::string. Since you are not saving it anywhere, it gets destroyed. Anything that happens afterwards depends solely on your luck.
I recommend using an istringstream.