Converting a std::list to char*[size] - c++

for some reason I cannot explain, every single item in the character array...is equal to the last item added to it...for example progArgs[0] through progArgs[size] contains the value of the last item.
I cannot figure out what I'm doing wrong for the life of me. Any suggestions?
int count = 0;
char *progArgs[commandList.size()]
for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++)
{
char item[strlen((*t).c_str())]; //create character string
strcpy(item, (*t).c_str()); //convert from const char to char
progArgs[count] = item;
count++;
}
edit:
Thanks for all the quick responses everyone...I see what you are talking about

You're assigning the same pointer (the address of the first element of the stack array item) to each element of progArgs, then repeatedly overwriting that memory. You can do:
progArgs[count] = strdup(t->c_str());
and get rid of the first two lines of the for body.
strdup allocates memory, so you will have to free each element with free later. Also, you were not allocating a character for the NUL-terminator. You need would strlen + 1. However, this is not an issue with strdup, since it allocates for you.

progArgs is an array of pointers to char.
You set each of these pointers to point to item. item is a local variable in the loop, so as soon as the loop exits, item no longer exists and the pointers are no longer valid[*]. However, in your C++ implementation, they all still point to the bit of memory which used to be the array item on the stack. This memory contains whatever it was last used for, which is the sequence of characters from the last string in the list.
If you want to copy a list of strings to an array, it would be better if possible to use an array of strings:
std::string progArgs[commandList.size()] // if your compiler has C99 VLAs as an extension
int count = 0;
for(std::list<std::string>::iterator t=commandList.begin(); t != commandList.end(); ++t) {
progArgs[count] = *t;
++count;
}
Or even better, use a vector instead of an array:
std::vector<std::string> progArgs(commandList.begin(), commandList.end());
[*] to be more precise, the scope of item is a single repeat of the loop, it's nominally "created" and "destroyed" each time around. But this doesn't do any work - on your C++ implementation the same region of memory is re-used each time, and there's no work needed to create or destroy an array of char on the stack.

item has scope local to the loop. The propArgs array therefore contains a bunch of stack-based pointers, likely all the same. You can examine how this works in the debugger, just step thru the loop twice and it should be clear what's going on.
By the time you exit the loop, the buffer addressed by the common pointer contains the most recently-copied c_str().
You could fix this by doing
char* item = new char[strlen((*t).c_str()) + 1];
but then you'd have to delete[] all the propArgs array entries when you exit the loop.
This code shows a fundamental lack of understanding of memory management such that further reading might be useful before restructuring the code. If the code used here was in only slightly more complex context than this example, it might just crash since any access of propArgs outside the loop would rely on an invalid (no longer in scope) item.

The char array item is local variable and is available only within the for loop.
Instead allocate it dynamically.

You're right:
for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++)
{
char item[strlen((*t).c_str())]; //create character string
...this does create an array, but it creates it on the stack, so when you reach the end of its scope, it gets destroyed.
strcpy(item, (*t).c_str()); //convert from const char to char
progArgs[count] = item;
count++;
}
...and this closing brace marks the end of its scope. That means you're creating a string, putting it into your array, then destroying it before you add the next one. Thanks to the fact that you're creating them all on the stack, each new one you create is being created in exactly the same place as the previous one, so it's no surprise that at the end of it all, you have a bunch of identical strings.
Perhaps it would be better if you told us what you're trying to accomplish here, so we can help you do that.

You're setting progArgs[count] to the same item every time!
int count = 0;
char *progArgs[commandList.size()]
for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++)
{
char * item = new char[strlen((*t).c_str()) + 1]; //create new character string
strcpy(item, (*t).c_str()); //convert from const char to char
progArgs[count] = item;
count++;
}
Then remember to call delete[] for each element in progArgs.
Personally, I'd create an array of string and convert to char * on the fly as needed.

Related

Insert char * with new into a vector C++

I have code sample like below..
std::vector<char*> vNameList;//it will be defined globally..
int main(int argc, char* argv[])
{
CollectName();
for(int i = 0; i<(int)vNameList.size(); i++)
{
printf("\n %s" , vNameList[i]);//Here gabage values are getting printed on console
}
return 0;
}
void CollectName()
{
char *Name = new char[sizeof(NAME)+1];//NAME datatype is defined having size of 32 char
//processing for Name is performed , which includes assigning Name variable with value..
//now insert it into vector
vNameList.push_back(Name);
delete[] Name; //at this Name value inserted into vector become garbage
}
I believe if we initialize char * with new it must be deleted to avoid memory leaks. But this is leading to modifying values from a vector.
Please guide me so that I can correct my code which will give me correct values.
I have some restriction to use Char * only , so suggest way to achieve this using char*.
You can correct your code by deleting the pointers only after you're done using them (assuming you actually have code which uses the pointers. Your example code doesn't print anything at all, garbage or otherwise).
But it's usually better design to store character strings in a std::string and when you store std::strings in a std::vector, you no longer need to manage the memory manually.
It is because the name of array is treated as pointer in c++(or c, it is inherted).
Therefore when you do
vNameList.push_back(Name);
It inserts the char * into vector,i.e the pointer to the first char(ans hence the string) to the vector, but you delete the pointer afterwards , therefore you get junk values. However if you don't delete the pointer , it works just fine as the pointer still exists , but this way you will not free up memory. Therefore : DONOT USE THIS
here it is : LIVE EXAMPLE
To avoid this hassle : you should use
std::vector<std::string> vNameList;
instead.

Allocate extra memory to the character array C++

I have this problem where I have a string and I pass it to the function as a character pointer.
void test(char * str) {
....
}
where str = "abc". Now I want to add few extra characters to the end of this string without creating a new string. I do not want to use strcat as I do not know how many characters I am adding to the end of the string and what I am adding. I was trying to work with realloc but it does not work as the str is allocated on stack.
Is there any way I can increase the size of the char array dynamically?
UPDATE :
I was asked a question which involved this in my interview. I was asked to do it without using additional space. So if I allocate memory using malloc I am technically using additional space right?
Thanks
No, especially if the string is allocated on the stack. The stack space is fixed at compile-time. You must either allocate more space initially, or allocate a new array with more space and strcpy it over.
If you are using C++ - then stick to std::string and forget the whole deal with char *.
However if you wish to use the char * for strings, then allocate a new character array and strcpy() from one string to another. Do not forget to deallocate the original char * memory to avoid memory leaks.
I was asked a question which involved this in my interview. I was asked to do it without using additional space. So if I allocate memory using malloc I am technically using additional space right?
How can you increase the length of the string without adding additional space?
You must delete the old string and allocate a new one with new with the length you want.
Sorry, no. A dynamic variable/array cannot be resized up. The problem is that another variable, or even another call frame could be immediately following the variable in question. These cannot be moved to make space as there may be pointers to these objects elsewhere in the code.
void test(string &str) {
....
str += "wibble";
}
Seems to work for C++
Rather than using realloc(not to be done on stack) or strcpy(uses extra buffer space) you may store the new values from the byte right after the input string. In the simple example below, I begin with "abcd" and add three z's at the end in the function fn.
void fn(char *str)
{
int len = strlen(str);
memset(str+len, 'z', 3);
str[len+3] = 0;
return;
}
int main()
{
char s[] = "abcd";
printf("%s\n", s);
fn(s);
printf("%s\n", s);
}
Output:
abcd
zzz
This way can be extended to adding different strings in front of original one.

Parsing a string to a pointer array of chars: char[0] contains the full string and [1] onward contains nothing

I'm trying to parse a simple string to an array of *char and for some reason when I use string.c_str() it puts the entire string into *char[0] and the rest of the array is left blank (I originally thought that chars could only hold one ASCII character but I guess that they act differently as pointers), could anyone have a scan through my function and tell me if there are any obvious mistakes?
static void SetGame()
{
// Variable Initiation
int myRandom = rand() % (numOfWords - 1);
lengthOfString = wordArray[myRandom].length();
// Reinitiate Pointer Arrays
stringArray = new string[lengthOfString];
isDiscoveredArray = new bool[lengthOfString];
// Parse string to the array of characters
*stringArray = wordArray[myRandom].c_str();
// Set each boolean array value to false
for (int i = 0; i < sizeof(isDiscoveredArray); i++)
{
isDiscoveredArray[i] = false;
}
}
Here are my decelerations of the pointers
// Global Variable and pointer Declerations
string *wordArray;
int numOfWords;
string *stringArray;
int lengthOfString;
bool *isDiscoveredArray;
Any ideas? Thanks.
You are mixing types here. First you build an array of strings and store it in a pointer, then you assign to the first element a const char* coming from c_str. The code you currently have would be if your were creating a string for every character in your selected word.
Make your "stringArray" a const char* to fit with the code you already have, but remove the memory allocation.
You've got an array of std::string and when you deference it (i.e. *stringArray) its the same as stringArray[0], so that is why it always going into the first element of your array.
Since you are setting your array have the same number of elements as the string your are copying has characters, you may just want to use a string rather than a string array to copy it into.
If it supposed to be char* (character array) then you will need to explicitly copy the source, which is the result of wordArray[myRandom].c_str(), into your character array rather than using simple assignment.

Passing 2-D array with dynamic size between functions in C/++

This is "popular" question so I already checked the similar threads but still didnt resolve my issue.
How can I declare 2-D array to hold "strings" - I need array of array of chars AFAIK - and use it as argument to 5 functions one after another where I can pass it by reference and update the content dynamically so following function can compare it. (I might get 10 "strings" or even empty array, so I want to do it correctly with dynamic array coz array content is different from system to system).
"string" => C style string aka array of chars. MAXLEN < 32;
C solution would be more disirable but if vectors can work, why not.
One possible solution in C is as follows:
char **p_strings = calloc(num_strings, sizeof(*p_strings));
for (i = 0; i < num_strings; i++)
{
// Allocate storage for the i-th string (always leave room for '\0')
p_strings[i] = calloc(len_string[i]+1, sizeof(*p_strings[i]));
}
...
// Call a function
my_function(p_strings, num_strings);
You will need to remember to free all this data when you're done with it.
If you need to alter the length of a string, or change the number of strings, you will have to do some fairly painful reallocation. So if you're working in C++, you should probably just be using a std::vector<std::string>.
std::vector<std::string> strings;
strings.push_back("Foo");
strings.push_back("Bar");
...
my_function(strings);
You can even get const pointers to C-style strings for each element, using c_str().
Assuming C++; for this I see no problem with using a vector to string (the string serves as the second dimension):
void foo(vector<string> v) {
cout << v[0]; // Assuming the elements exist!
}
int main(int argc, char *argv[])
{
vector<string> vString; // Make the vector
vString.push_back("something"); // Add a string
foo(vString); // Print out 'something'
}
In your edit you also described that the only thing that will change would be the actual string, so instead of push_backing your strings when they are needed, you can init the vector with the length:
vector<string> vString(10); // Assuming a size of 10
and then use them normally:
vString[4] = "something";
and (in response to the comment), to resize at runtime:
vString.resize(15); // Make it bigger, generates new blank strings

Reversing a string/sequence of characters using only pointers

I'm working on an assignment that requires myself to reverse a sequence of characters, which can be of any given type, using a pointer to the "front" of the sequence and a pointer to the "end" of the sequence.
In my current build, I begin by first attempting to switch the "front" and "end" characters. However, I receive an "access violation" during runtime.
My code at the moment:
#include <cstdlib>
#include <string>
#include <iostream>
using namespace std;
class StrReverse
{
public:
StrReverse(); //default constructor
void revStr(); //reverses a given c-string
private:
typedef char* CharPtr;
CharPtr front;
CharPtr end;
CharPtr cStr;
};
int main()
{
StrReverse temp = StrReverse();
temp.revStr();
system("pause");
return 0;
}
//default constructor
StrReverse::StrReverse()
{
cStr = "aDb3EfgZ";
front = new char;
end = new char;
}
//reverses a given string
void StrReverse::revStr()
{
for(int i = 0;i < 4;i++)
{
front = (cStr + i);
end = (cStr + (7 - i));
*front = *end;
}
}
The key restriction with this problem is that the reversal must be done using pointers. I realize that simply reversing a string is trivial, but this restriction has me scratching my head. Any constructive comments would be greatly appreciated!
You assign the string literal "aDb3EfgZ" to cStr, and string literals can't be modified. Your compiler most likely stores the string literal in read only memory, and when you try to write to *front you get an access violation because of that.
To get a modifiable string, make a copy of the literal. For example:
const char *cLit = "aDb3EfgZ";
cStr = new char[strlen(cLit)+1];
strcpy(cStr, cLit);
For further detail see for example this question and the ones mentioned there in the "Linked" section.
There are several problems with your code. For starters, why the class;
this is something I'd expect to be done with a simple function:
void reverse( char* begin, char* end );
And you don't need an index, since you've got the pointers already; you
can just increment and decrement the pointers.
Also, why do you allocate memory in your constructor. Memory that you
never use (or free).
Finally, you don't really inverse anything in your loop. You need to
swap the characters, not just copy the one at the end into the one at
the beginning.
And as for the access violation: a string literal is a constant. You
can't modify it. If you want to do the reverse in place, you'll need to
copy the string somewhere else (or use it to initialize an array).
Your constructor is gonna leak memory because you loose the pointers you allocate the front and end, those allocations aren't even needed. As for your problem, you can loop though the string to find the end using while(*endptr) endptr++;, from there the size of the string is endptr - startptr; which you use to allocate a temp buffer so you can do while(startptr != endptr) *tempbuf++ = *endptr--; then free the old string and set the temp buffer as the new string
The basic technique for an in-place reversal:
get a pointer (call it 'left') to the first character in the string.
get a pointer (call it 'right') to the last character in the string (not counting the trailing NUL character)
while the left pointer is less than the right pointer
swap the characters located by each pointer
increment the left pointer
decrement the right pointer
That's about all there is to it. Production of a reversed copy of the string requires a bit more work.