Segmentation fault in constructor when using strcpy - c++

Hi guys I'm writing a program that reads NMEA sentences for a university assignment and I'm having trouble with segmentation fault. Can anyone help me fix it, please?
NmeaSentence::NmeaSentence(std::string sentence) {
const char *temp = sentence.c_str();
char *c_sent;
strcpy(c_sent, temp);
char *pch;
for(int i = 0; i < MAX_SENTENCE_PARTS; i++){
pch = strtok(c_sent, ",");
this->sentenceParts[i] = pch;
}
this->sentence = sentence;
this->sentenceType = sentenceParts[0];
}
The error seems to be happening at strcpy. What am I doing wrong?

You don't allocate memory for c_sent. That's undefined behaviour.
Use char *c_sent = new char[sentence.size() + 1];. I've added space for the null terminator. Don't forget to call delete[] c_sent; before the function exits.
(By the way, temp is valid for the lifetime of sentence, unless it's modified in any way.).

The temporary string c_sent is uninitialized.
char * c_sent
to
char * c_sent = strdup(sentence.c_str());
Dont forget to free, before exit.
free(c_sent);
You won't need temp this way.

The member function has several defects.
If the parameter of the function is not changed then it would be better to declare the function as
NmeaSentence::NmeaSentence( const std::string & sentence);
As it was already said you did not allocate memory where you are going to copy sentence. Pointer c_sent was not initialized by the address of an allocated memory.
The second defect is that pch always points to the same address in c_sent because you are incorrectly using function strtok. You should use it the following way
char *pch = strtok(c_sent, ",");
for(int i = 0; i < MAX_SENTENCE_PARTS && pch; i++){
this->sentenceParts[i] = pch;
pch = strtok( NULL, ",");
}
Also it is not clear how you will determine how many parts the string contains.

Related

C++ Shell in Unix, execv: Dynamically create and Return a usable second parameter from a function

Everywhere I've looked for answers to this question, I see people making one small char * array of size like two and hardcoding in paths for execv. What I need to do is to take a string of parameters with the path as the first set of characters, tokenize them, and then put them in an array of char *s that execv will accept.
here is my tokenization function
char ** stringToVectorToCharArray(string inputString)
{
stringstream ss(inputString);
cout << "\n inputString is: " << inputString <<"\n";
vector<string> tokens;
tokens.clear();
while(ss >> inputString)
{
tokens.push_back(inputString);
}
int size = tokens.size();
char **args = new char*[size + 1];
int i = 0;
for(; i < size; i++)
args[i] = const_cast<char *>(tokens.at(i).c_str());
args[i + 1] = (char *) 0;
return args;
}
And this is called from
char **args = stringToVectorToCharArray(inputString);
execv(executeChar, args);
Within the Child section of my fork() if-else statements for flow control.
I get a bad_alloc error, but I'm not sure which of my allocation statements are right, if any are for that matter. I know the return has to be in the form
char *const argv[]
But I'm not sure how to set that up.
You are returning memory from a local variable (tokens) from your function.
for(; i < size; i++) {
// stores pointer to local memory: args[i] = const_cast<char *>(tokens.at(i).c_str());
args[i] = new char[tokens.at(i).size()+1]; // Create dynamically allocated copy
strcpy(args[i], tokens.at(i).c_str());
}
The above should fix the problem. Technically, this would create a memory leak, since the memory is never deallocated, but your call to execv will replace your executable and effectively deallocate the memory.

Memcpy Char Pointers

I have this simple program in which I want to concatenate two char pointers using memcpy, but I get access violation reading location on the memcpy line.
char *first = new char[10], *second=new char[10];
first="Hello ";
printf("\second: ");
scanf("%s",&second);
memcpy(first,second,strlen(second)+1);
printf ("Result: %s\n", first);
Because copying into a constant gets me the violation, I tried this:
char *first = new char[20], *second="world!";
printf("first: ");
scanf("%s",&first);
memcpy(first,second,strlen(second)+1);
printf ("Result: %s\n", first);
which gets me access violation writing location. How should I concatenate correctly the two pointers?
Your memcpy is equivalent to memcpy ("Hello ", second, strlen(second)+1);. Copying into a constant is (on some platforms, apparently including yours) an access violation.
char *first = new char[10], *second=new char[10];
first="Hello ";
First you make first point to some memory you allocated. Then you throw that pointer away and make it point to a static string. That's not what you mean. Maybe you meant:
strcpy (first, "Hello ");
This copies the constant's data into the space first points to.
char * concat(const char * first, const char * second)
{
int lf = strlen(first);
int ls = strlen(second);
int len = lf + ls;
char * rb = new char[len+1];//You need this +1 here
memcpy(rb, first, lf);
memcpy(rb+lf, second, ls);
rb[len] = 0;
return rb;
}
int main ()
{
char *first = new char[10], *second=new char[10];
strcpy(first, "first");//This is an unsafe way. You can take the value from anywhere possible
strcpy(second, "second");//This is an unsafe way. You can take the value from anywhere possible
char * third = concat(first, second);
cout << third << endl;//Don't use cout << concat(first, second) << endl; since it leads to a emory leak
delete [] third;
return 0;
}
You can't concatenate two string without using extra memory, since every time you need a memory block of size of the sum +1 (or more) of the two given strings.
Change
scanf("%s", &first);
to
scanf("%s", first);
You access the wrong memory when scaning.

Why does this combination of strtol and strtok not work?

Could anyone tell me what is wrong with this code?
for(int i=0;i<4;i++)
{
long int a = strtol(strtok("1-2-3-4","-"),(char**)NULL,10);
cout << a <<endl
}
I'm running on Solaris Unix. It's giving me a segmentation fault.
The fault is in strtol().
The error is with the strtok call, not with strtol. You can't call strtok on a string literal, since it's going to try to modify the string. Modifying a string literal causes undefined behaviour in C++.
The problems are legion.
I would expect that the core dump is because the string "1-2-3-4" is stored in read-only memory, so when strtok() modifies it (to isolate the first token), the program crashes. You say the crash is in strtol(); that would suggest that the return value from strtok() is NULL.
The first call to strtok() uses the string as an argument; the second call passes NULL in its place to indicate 'continue where you left off last time'. As written, if the string was modifiable, then you'd parse 1 four times.
This is closer to correct (though untested):
char input[] = "1-2-3-4";
char *data = input;
for (int i = 0; i < 4; i++)
{
char *token = strtok(data, "-");
if (token != 0)
{
long int a = strtol(token, NULL, 10);
cout << a << endl;
}
data = NULL;
}
In general, you need to do error detection from strtol(); further, doing so is quite fraught. However, with the sample string, you would not have to worry about that.
As the problem is already discussed, I'd like to show an alternate approach :
#include <stdio.h>
#include <string.h>
int main ()
{
long int a;
char str[] ="1-2-3-4";
char * pch;
pch = strtok (str,"-");
while (pch != NULL)
{
a = strtol(pch,(char**)NULL,10);
cout << a <<endl;
pch = strtok (NULL, "-");
}
return 0;
}

invalid conversion from 'char' to 'char*' using strcpy

Ok so here are the parts of my code that I'm having trouble with:
char * historyArray;
historyArray = new char [20];
//get input
cin.getline(readBuffer, 512);
cout << readBuffer <<endl;
//save to history
for(int i = 20; i > 0; i--){
strcpy(historyArray[i], historyArray[i-1]); //ERROR HERE//
}
strcpy(historyArray[0], readBuffer); //and here but it's the same error//
The error that i'm receiving is:
"invalid conversion from 'char' to 'char*'
initializing argument 1 of 'char* strcpy(char*, const char*)'
The project is to create a psudo OS Shell that will catch and handle interrupts as well as run basic unix commands. The issue that I'm having is that I must store the past 20 commands into a character array that is dynamically allocated on the stack. (And also de-allocated)
When I just use a 2d character array the above code works fine:
char historyArray[20][];
but the problem is that it's not dynamic...
And yes I do know that strcpy is supposed to be used to copy strings.
Any help would be greatly appreciated!
historyArray points to (the first element of) an array of 20 chars. You can only store one string in that array.
In C, you could create a char** object and have it point to the first element of an array of char* objects, where each element points to a string. This is what the argv argument to main() does.
But since you're using C++, it makes a lot more sense to use a vector of strings and let the library do the memory management for you.
Stop using C idioms in a C++ program:
std::deque<std::string> historyArray;
//get input
std::string readBuffer;
std::getline(std::cin, readBuffer);
std::cout << readBuffer << std::endl;
//save to history
historyArray.push_front(readBuffer);
if(historyArray.size() > 20)
historyArray.pop_back();
As a result, we have:
No buffer-overflow threat in readBuffer / getline()
No pointers, anywhere, to confuse us.
No arrays to overstep the ends of
Arbitrarily long input strings
Trivially-proven memory allocation semantics
Two solutions. The first is if you for some reason really want arrays, the other is more recommended and more "C++"ish using std::strings.
char * historyArray[20]; // Create an array of char pointers
// ...
historyArray[i] = new char[SIZE]; // Do this for each element in historyArray
Then you can use strcpy on the elements in historyArray.
Second solution which I repeat is recommended (I've fixed a few other things):
string historyArray[20];
getline(cin, readBuffer); // Make readbuffer an std::string as well
cout << readBuffer << endl;
for(int i = 19; i > 0; i--){ // I think you meant 19 instead of 20
historyArray[i] = historyArray[i-1];
}
historyArray[0] = readBuffer;
historyArray[i] is a char. It is a single character. You want to use a sting. Your fundemental problem is that historyArray is a char* which means that it points to a memory range containing characters. You want it to be a char** which is a pointer to a pointer to a string. Your initialization code would be
char** historyArray;
historyArray = new char* [20];
for (int i = 0; i < 20; i++)
{
historyArray[i] = new char [512]; //Big enough to have a 512 char buffer copied in
}
Error 1: You're indexing past your array bounds with i being set to 20.
Error 2: historyArray[i] is a char, not a char *. You need &historyArray[i].
strcpy(&historyArray[i], &historyArray[i-1]);
Array notation gives references while strcopy wants pointers. Convert references to pointers with address-of (&) operator.
char * historyArray;
historyArray = new char [20];
//get input
cin.getline(readBuffer, 512);
cout << readBuffer <<endl;
//save to history
for(int i = 20; i > 0; i--){
strcpy(&(historyArray[i]), &(historyArray[i-1])); //ERROR HERE//
}
strcpy(historyArray, readBuffer); //and here but it's the same error//
But that will only fix the compiler errors, not the logical errors in the code. Your using C++ so the string solution:
vector<string> history;
cin.getline(readBuffer,512);
history.push_back(readBuffer);
Alternatively if you want one long string containing everything from readBuffer:
string history;
cin.getline(readBuffer,512);
history = history += string(readBuffer);
For example...

Basic Custom String Class for C++

EDIT: I don't want to delete the post because I have learned a lot very quickly from it and it might do someone else good, but there is no need for anyone else to spend time answering or viewing this question. The problems were in my programming fundamentals, and that is something that just can't be fixed in a quick response. To all who posted, thanks for the help, quite humbling!
Hey all, I'm working on building my own string class with very basic functionality. I am having difficulty understand what is going on with the basic class that I have define, and believe there is some sort of error dealing with the scope occurring. When I try to view the objects I created, all the fields are described as (obviously bad pointer). Also, if I make the data fields public or build an accessor method, the program crashes. For some reason the pointer for the object is 0xccccccccc which points to no where.
How can a I fix this? Any help/comments are much appreciated.
//This is a custom string class, so far the only functions are
//constructing and appending
#include<iostream>
using namespace std;
class MyString1
{
public:
MyString1()
{
//no arg constructor
char *string;
string = new char[0];
string[0] ='\0';
std::cout << string;
size = 1;
}
//constructor receives pointer to character array
MyString1(char* chars)
{
int index = 0;
//Determine the length of the array
while (chars[index] != NULL)
index++;
//Allocate dynamic memory on the heap
char *string;
string = new char[index+1];
//Copy the contents of the array pointed by chars into string, the char array of the object
for (int ii = 0; ii < index; ii++)
string[ii] = chars[ii];
string[index+1] = '\0';
size = index+1;
}
MyString1 append(MyString1 s)
{
//determine new size of the appended array and allocate memory
int newsize = s.size + size;
MyString1 MyString2;
char *newstring;
newstring = new char[newsize+1];
int index = 0;
//load the first string into the array
for (int ii = 0; ii < size; ii++)
{
newstring[ii] = string[ii];
index++;
}
for(int jj = 0; jj < s.size; jj++, ii++)
{
newstring[ii] = s.string[jj++];
index++;
}
//null terminate
newstring[newsize+1] = '\0';
delete string;
//generate the object for return
MyString2.string=newstring;
MyString2.size=newsize;
return MyString2;
}
private:
char *string;
int size;
};
int main()
{
MyString1 string1;
MyString1 string2("Hello There");
MyString1 string3("Buddy");
string2.append(string3);
return 0;
}
EDIT:
Thank you everyone so far who has responded and dealing with my massive lack of understanding of this topic. I'll begin to work with all of the answers, but thanks again for the good responses, sorry my question is vague, but there isn't really a specific error, but more of a lack of understanding of arrays and classes.
Here's just the mistakes from the first constructor.
MyString1()
{
//no arg constructor
char *string; //defines local variable that hides the member by that name
string = new char[0]; //sort of meaningless
string[0] ='\0'; //not enough room for that (out-of-bounds)
std::cout << string;
size = 1; //I don't think you should count null as part of the string
}
Similar mistakes elsewhere.
Also you should pass parameters in a more careful way.
MyString1(const char* source); //note const
MyString1 append(const MyString1& what); //note const and reference
If the latter is correct, also depends on what it is supposed to do. Based on std::string the expected result would be:
MyString1 a("Hello "), b("world");
a.append(b);
assert(a == "Hello world");
Some comments on your code:
MyString1()
{
//no arg constructor
Perhaps your instruction requires it, but in general this is the kind of comment that's worse than useless. Comments should tell the reader things that aren't obvious from the first glance at the code.
char *string;
string = new char[0];
string[0] ='\0';
This invokes undefined behavior. Calling new with zero elements is allowed, but you can't dereference what it returns (it may return a null pointer, or it may return a non-null pointer that doesn't refer to any storage). In most cases, you're better off just setting the pointer to NULL.
std::cout << string;
What's the point of writing out an empty string?
size = 1;
The string is empty so by normal figuring, the size is zero.
//constructor receives pointer to character array
Still useless.
MyString1(char* chars)
Since you aren't (or shouldn't be anyway) planning to modify the input data, this parameter should be char const *.
{
int index = 0;
//Determine the length of the array
while (chars[index] != NULL)
index++;
While this works, "NULL" should really be reserved for use as a pointer, at least IMO. I'd write it something like:
while (chars[index] != '\0')
++index;
Unless you're using the previous value, prefer pre-increment to post-increment.
//Allocate dynamic memory on the heap
As opposed to allocating static memory on the heap?
MyString1 MyString2;
Using the same naming convention for types and variables is confusing.
while (string[index] != NULL)
Same comment about NULL as previously applies here.
MyString1 append(MyString1 s)
IMO, the whole idea of this function is just plain wrong -- if you have a string, and ask this to append something to your string, it destroys your original string, and (worse) leaves it in an unusable state -- when you get around to adding a destructor that frees the memory owned by the string, it's going to cause double-deletion of the storage of a string that was the subject (victim?) of having append called on it.
I'd consider writing a private "copy" function, and using that in the implementations of some (most?) of what you've shown here.
As a bit of more general advice, I'd consider a couple more possibilities: first of all, instead of always allocating exactly the amount of space necessary for a string, I'd consider rounding the allocation to (say) a power of two. Second, if you want your string class to work well, you might consider implementing the "short string optimization". This consists of allocating space for a short string (e.g. 20 characters) in the body of the string object itself. Since many strings tend to be relatively short, this can improve speed (and reduce heap fragmentation and such) considerably by avoiding doing a heap allocation if the string is short.
index doesn't start at 0 in the second while loop in your append function. You should probably be using for loops. Oh, and you're using the wrong form of delete. You should be using delete[] string because string is an array.
There are numerous other style issues, and outright errors, but the thing I mentioned first is the basic error you were encountering.
I would write the append function in this way:
void append(MyString1 s)
{
//determine new size of the appended array and allocate memory
int newsize = s.size + size;
char *newstring = new char[newsize+1];
int destindex = 0;
for (int index = 0; index < size; ++index) {
newstring[destindex++] = string[index];
}
for (int index = 0; index < s.size; ++index) {
newstring[destindex++] = s.string[index];
}
newstring[destindex] = '\0';
delete[] string;
string = newstring;
}