Variables being overwritten when using new - c++

I'm having a problem with dynamic memory allocations in c++. I have to write a function that solves a maze stored in a .dat file. The walls are made of # separated by a space, and some points are words that need to be read in to an arbitrary length c string. This c string is then stored in the maze array. My problem is that my c strings keep overwriting previous ones in memory. How can I tell the program not to overwrite certain blocks of memory?
This is the function the initialises the maze array:
int LoadMaze(Maze& maze, int& width, int& height, char fname[])
{
ifstream ifs(fname);
int stringLength;
char inputChar;
char* newCString;
if (ifs.good())
{
ifs >> width >> height;
maze = new char*[width*height];
for (int i=0;i<width*height;i++)
{
stringLength = 0;
inputChar = '1';
while(inputChar != ' ')
{
inputChar = ifs.get();
if(inputChar != ' ' && inputChar != '\n')
{
newCString = resizeChar(newCString, stringLength);
newCString[stringLength++] = inputChar;
}
}
//maze = resizeMaze(maze, i);
maze[i] = newCString;
}
ifs.close();
return 1;
}
else
{
cerr << "File not found." << endl;
return 0;
}
}
Since the C string has to be an arbitrary length, resizeChar increases the cstring size by one. Then the pointer to that cstring is stored in maze.
char* resizeChar(char* stringStart, int oldSize)
{
int counter = 0;
char* tempPtr = new char[oldSize + 1];
for(counter = 0; counter < oldSize; counter++)
{
*(tempPtr + counter) = *(stringStart + counter);
}
delete[] stringStart;
return (tempPtr);
}

You are passing an uninitialized value to your function:
char* newCString;
....
newCString = resizeChar(newCString, stringLength);
To fix this you need to give newCString a sensible initial value, and make sure that resizeChar can handle that scenario.
It would be better to initialize newCString each time around the loop. That also avoids the problem that you are using the same buffer for every row of the maze.
Another major problem is that you never null-terminate the strings you are building. So once you have gone maze[i] = newCString;, that row is just pointing to some characters but you have lost the information of how many characters are in the string. And if you try to output this string then you will buffer overflow and start outputting garbage.
You need to allocate 1 more byte than the number of characters in the string, and make the last one of those be '\0'.

The question is how do I stop new values of newCString from being written in the same memory location as previous ones?
If you replace the old value of a variable with a new one, then the old value will be overwritten because a variable, during its life, does not move in memory. If you don't want to change the value, simply don't write code that changes it. Set the value of newCString to the value you want it to hold and do not change its value from then one.

Related

C++ Dynamic Ragged Array

I have been trying to figure out this assignment for hours and can't grasp it yet. I'm trying to read in names from a txt document, which is working, and I need to store them in an char pointer array. Once the number of names is as big as the array size, I need to use REALLOCATION to make the array bigger (I can't use vector library).
I'm struggling with changing the name array size to make it bigger and deleting the old array from memory (it just crashes when I write delete [] names;).
Here is my currently broken code:
int numNames = 2;
char * names[numNames] = {};
ifstream namesFile("names.txt");
//get names from user, put names in ragged array
int i = 0;
while (i < numNames) {
if (namesFile.good() && !namesFile.eof()) {
//add name to ragged array
names[i] = new char[257];
namesFile >> setw(256) >> names[i];
i++;
if (i == numNames) {
//need a bigger array
numNames *= 2;
char * temp[20] = {};
for (int j = 0; j < numNames / 2; j++) {
temp[j] = names[j];
}
delete [] names;
names = temp;
}
}
else {
//end of file or corrupt file
break;
}
}
namesFile.close();
Any help is appreciated!
The following statement does not do any dynamic allocation. It just declares an array of pointers to char (char*) on a stack of size numNames. So, it is not dynamic by any means:
char * names[numNames] = {};
As such, you cannot change its size.
Instead you need to create a pointer to the array like the following:
char **names = new (char*)[numNames];
Same story for your temp down the road. Now you are free to delete/new and to assign pointers as well: names = temp.
Now, you need to read your char data from a file line by line and put it in the 'names' array. When you read a string, you can allocate space for it in the array member, i.e.
names[i] = new char [strlen(inputString) + 1]; // you need '+1' for termination char
and you can copy data from your string after allocation, i.e.
strcpy(name[i], inputString); // this is a standard 'c' string copy
you can also use std::copy or a for loop do do a copy or whatever. Another method is to use a standard 'c' malloc function to do allocation:
name[i] = (char *)malloc(strlen(inputString) + 1);
The difference is that when you would need to free memory, you would use delete[] name[i] in the first case and free(name[i]) in the second. Though it looks like you do not need to free the memory in your task.
Now you just have to figure out how to read from the file.

Filling and comparing char* inside a function

I wrote the function readChar() which is designed to read the characters send by my WiFi module one by one(function works has advertised) and pass them to a char buffer of increasing size. The function should stop when char *endChar (multiple characters) have been detected or the number of character returned by timedRead() has exceeded size_t length.
I have several issues:
1/. I don't understand the syntax (found inside the Arduino Stream library) :
*buffer++ = (char)c;
Can you explain how the array buffer gets filled?
And why buffer[index] = (char)c; doesn't work here?
2/. I would like to compare buffer and endChar in the loop, possibly by using strcmp(buffer,endChar) (maybe there is a better way). But that doesn't seem to work. In fact when printing the ASCII values of my char *buffer then seem to increment from the end of the buffer. E.G.:
So what is the best way to do that comparison?
The code, inserted in the loop:
_dbgSerial->println("buffer");
for (int i = 0; i < 32; i++){
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
prints:
buffer
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,0,0,
Here is the function readChar():
size_t Debugwifi::readChar(char *endChar, char *buffer, size_t length) {
if (length < 1) return 0;
size_t index = 0;
while (index < length) {
int c = timedRead();
if (c < 0 ) break;
//buffer[index] = (char)c;
*buffer++ = (char)c;
_dbgSerial->println("buffer");
for (int i = 0; i < 32; i++){
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
if (strcmp(buffer,endChar)==0) {
break;
_dbgSerial->println("brk");}
index++;
}
return index;
}
As Rickard has explained, *buffer++ = (char)c; is how you assign a character to the memory a pointer points at, and then increment the pointer.
However, your function has a lot of problems - you keep comparing unset memory with *endChar. I suggest:
size_t Debugwifi::readChar(const char * const endStr, // const pointer to const.
char * const buffer, const size_t length) {
if (length < 1) return 0;
const size_t endLen = strlen(endStr);
for (size_t index = 0; index < length; index++) {
const int c = timedRead();
if (c < 0 ) break;
buffer[index] = (char)c;
// Debug
_dbgSerial->println("buffer");
for (size_t i = 0; i < length; i++){ // Better to use size_t here,
// and compare against length not 32
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
// Finished?
if (index >= endLen) {
if (memcmp(&buffer[index-endLen], endStr, endLen)==0) {
_dbgSerial->println("brk"); // Must do this *before* "break"!
break;
}
}
}
return index;
}
I have added a lot of consts. It's hard to have too many.
The important point is that once you have read enough characters, to start comparing the last characters you have read to the end marker.
Note that this function does not remove the end marker, and if you pass a 32-byte zero-filled array and it reads 32 characters, the result will NOT be zero terminated.
Finally, I changed the argument name to endStr because I had expected endChar to be a pointer to a single character - not a NUL-terminated string.
*buffer++ = (char) c;
First writes the value of c to what buffer is currently pointing to.
Then it increments the buffer
This is also why your loop to print buffer doesn't work.
You start printing from the position after what was just filled.
This is also why your strcmp doesn't work. It doesn't actually compare what you have filled your buffer with. It compares the content beyond what have been filled.
If you want your printing code to work you should save the initial value of buffer before the loop;
const char *buffer_start = buffer;
Then use that in your printing code instead of buffer.

C++ Copying an array of chars using char* (no string libraries)

I am writing a C++ function that is supposed to duplicate an array of chars by copying each element character-by-character into a new array. Ideally, if I make the statements
char* a = "test";
char* b = copyString(a);
then both a and b should contain the string "test." However, when I print the copied array b, I get "test" plus a series of nonsense characters that seem to be the pointer. I don't want those, but I can't figure out where I'm going wrong.
My current function is as follows:
char* copyString(char* s)
{
//Find the length of the array.
int n = stringLength(s);
//The stringLength function simply calculates the length of
//the char* array parameter.
//For each character that is not '\0', copy it into a new array.
char* duplicate = new char[n];
for (int j = 0; j < n; j++)
{
duplicate[j] = s[j];
//Optional print statement for debugging.
cout << duplicate[j] << endl;
}
//Return the new array.
return duplicate;
}
For the purposes of understanding certain aspects of C++, I cannot use string libraries, which is where other answers I have found have fallen short in this case. Any help with this problem is greatly appreciated.
EDIT: I though my stringLength function was fine - perhaps I was wrong.
int stringLength(char* s)
{
int n;
//Loop through each character in the array until the '\0' symbol is found. Calculate the length of the array.
for (int i = 0; s[i] != '\0'; i++)
{
n = i + 1;
}
//Optional print statement for debugging.
// cout << "The length of string " << s << " is " << n << " characters." << endl;
return n;
}
You need to copy the 0 too. That's what a C-style string is, a null-terminated character array.
Really, all you need to do is add one to the length:
int n = stringLength(s) + 1; // include the '\0'
And then everything else will account for itself - you'll allocate an array of sufficient size, and copy the '\0' in your loop too.

Append user input to array in C++

I'm trying to write a program that asks for user inputs (one at a time, and continues until the user interrupts somehow) and stores them in an array. In python, I can easily append new inputs to the end of an existing list, but this doesn't work in C++. What's the easiest way to do this without involving vectors? I'm thinking of deleting the array each time and creating a new one that's larger, but this seems like a pain.
This is some code I wrote up to do this, it basically creates a new array and copies over data from the old array. Hopefully this can help you. To give you an example of its usage, there is a demonstation area that inputs data from stdin until the user types "END" and the prints it to stdout excluding the "END".
#include <cstdio>
#include <iostream>
#include <cstring>
//Assuming you are storing strings
//Set this to the appropriate max length. The name of this may be misleading,
const int MAX_STRING_LENGTH = 128; //any other suggestions?
char** userInput;
int userInputUsed;
int userInputSize;
void append (char* text, int textLength) {
//If we have used up all the space in the array
if (userInputUsed >= userInputSize) {
//How large you want the new array to be compared to
//the original size (userInputSize)
int newArraySize = 2*userInputSize;
//Create the new array
char** newUserInput = new char*[newArraySize];
//We are only creating the new part of the array
//Another way you could do this is to create the strings as you go
for (int i = userInputUsed;i < newArraySize;i++) {
newUserInput[i] = new char[MAX_STRING_LENGTH];
}
//Copy everything over, I am setting our pointers to the old data
for (int i = 0;i < userInputUsed;i++) {
newUserInput[i] = userInput[i];
}
//Delete the old array
delete[] userInput;
//Set the new array to the old array
userInput = newUserInput;
//Update the size of our array;
userInputSize = newArraySize;
}
//Copy the input to userInput
memcpy(userInput[userInputUsed], text, textLength);
userInputUsed++;
}
int main () {
//Initialise userInput, initialise to whatever size you deem fit
userInputSize = 1;
userInput = new char*[userInputSize];
for (int i = 0;i < userInputSize;i++) {
userInput[i] = new char[MAX_STRING_LENGTH];
}
//Start of demonstration
//Get input until the user types "END"
for (bool running = true;running;) {
char temp[MAX_STRING_LENGTH];
//Scans in until some whitespace, this may not work if
//you want to scan in whole lines which end in '\n'
//scanf("%s", temp);
//or
std::cin >> temp;
//End if input is "END"
if (strcmp(temp, "END") == 0) {
running = false;
} else {
append(temp, strlen(temp));
}
}
//Print out the user input, to see that it is inputed correctly
for (int i = 0;i < userInputUsed;i++) {
//printf("%s\n", userInput[i]);
//or
std::cout << userInput[i] << std::endl;
}
//End of demonstration
//Cleanup our user input
for (int i = 0;i < userInputSize;i++) {
delete[] userInput[i];
}
delete[] userInput;
//Stop the program from ending, you may not need this
//while(true);
return 0;
}
Feel free to comment or suggest improvements to this answer.

c++ Dynamic array using strings won't accept strings

I am trying to put the strings in a temporary array into a dynamic array. But the compiler just breaks when it hits that.
where dynaicArray is called:
string* dynamicArray = NULL;
Here is where it is breaking:
for (int i = 1; i <= (size); i++)
{
dynamicArray[i] = tempArray[i];
}
Where tempArray is filled:
void populateArray(int& size, string*& dynamicArray)
{
char decide;
string tempArray[100]; //Holds the strings until the size is known
bool moreStrings = true;
while (moreStrings == true)
{
cout << "\nEnter your string here:";
cin >> tempArray[size];
cout << "\nDo you want to enter another string? Y/N:";
cin >> decide;
decide = toupper(decide);
size ++;
dynamicArray = new string[size];
if (decide == 'N')
{
for (int i = 1; i <= (size); i++) //moves all of the strings from tempArray to dynamicArray
{
string temp;
temp = tempArray[i];
dynamicArray[i] = temp;
}
moreStrings = false;
}
}
}
PS: I know vectors are better. Unfortunately they're not an option.
Some design ideas:
the code in the if (decide == 'N') block is better placed after the while, to make the while smaller == more readable
once the above is implemented, you can set the moreStrings var directly with the result of your decide == 'N'; no need for an explicit if there anymore
you now do a dynamicArray = new string[size]; in each pass through the while, which is an enormous memory leak (you'r overwriting the newly created dynamic array with a new copy without reclaiming the old one out first - see dalete[])
as already mentioned: don't assume 100 will be enough - read "Buffer overflow" (only viable solution: make it a dynamic array as well and re-allocate it to a bigger one if it gets full)
better initialize size in the function before you use it - much safer; callers don't need to remember to do it themselves
C++ arrays are 0-based, so when you start copying them you'd also better start at 0 and not at 1
nitpick: for (int i = 1; i <= (size); i++): the () around size are superfluous
bonus advanced nitpick: use ++size and ++i in these contexts; it's a bit more efficient
you now use the var tmp to copy from the temp array to the dynamic one and the code is also somewhat structured to suggest you're using it to swap the strings between the two arrays (you're not) - rename the tmp variable or get rid of it altogether