I'm new to C++, trying to follow a tutorial series to learn the language, the challenge given for allocating memory is to allocate memory for 26 chars and then fill them with the alphabet, abcde... etc.
I thought I knew the solution but ran into this error:
Invalid address specified to RtlValidateHeap( 00490000, 0049D9EC ) the part that is throwing me off is the program executes fully, a-z but still throws this error
Here is my code:
char c = 'a';
char *pChar = new char[26];
for (int i = 0; i < 26; i++, pChar++, c++) {
*pChar = c;
cout << *pChar << flush;
}
delete[] pChar;
Sorry if the question is worded poorly, I am new to both c++ and stackoverflow.
When you say delete[] pChar; you are in fact attempting to delete what pChar is currently pointing at, which is not the same spot as where it was originally allocated.
In short, when you allocate something with new it puts some data about the allocation (size of the allocation for example so you do not need to say delete[26] pChar; like you had to when C++ was new) usually to the left of the newly allocated memory, and it is probably interpreting things you have written (the alphabet) as that information when trying to use it to free the memory, which is of course not going to work.
You should store a copy of the original pointer to the memory you have allocated instead and use that to delete, or perhaps a better option, use i and subscripts to index via pointer arithmetic instead like:
char c = 'a';
char *pChar = new char[26];
for (int i = 0; i < 26; i++, c++) {
pChar[i] = c;
cout << pChar[i] << flush;
}
delete[] pChar;
The trouble is that when control leaves the loop, pChar points to a location one past the end of the array. You then call delete[] on that pointer, which is like putting a wrecking ball through the wrong house.
As already mentioned in the other answers, you cannot call delete[] on a pointer you have changed since calling new []. It's undefined behavior.
delete [] needs to get passed the exactly same pointer value as you had achieved when calling new[].
And here's the most simple fix, without need to change pChar:
#include <iostream>
int main()
{
char c = 'a';
char *pChar = new char[26];
for (int i = 0; i < 26; ++i) {
pChar[i] = c; // access the character by index ...
std::cout << pChar[i] << std::flush; // access the character by index ...
// ++pChar; DON'T change the original pointer
++c;
}
delete[] pChar;
return 0;
}
Live Demo
Related
I am trying to create an array, which doubles every time it is completely filled.
#include <iostream>
using namespace std;
int* array_doubler(int* array, int size){
int *new_array = new int[size*2];
for(int i = 0; i < size; i++){
new_array[i] = array[i];
}
delete[] array;
return new_array;
}
int main()
{
int N = 10; // Size of array to be created
int *array = new int[0];
for(int i = 0; i < N; i++)
{
if(array[i] == '\0')
array = array_doubler(array, i);
array[i] = i*2;
}
//Printing array elemensts
for(int i = 0; i < N; i++)
cout << array[i] << '\t';
cout << '\n';
return 0;
}
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot). i.e. If i write:
int* p = new int[5];
then all the 5 blocks in memory p[0],p[1],p[2],p[3],p[4],p[5] have \0 in them, not just the p[5]. So the if(array[i] == '\0') in my main() calls array_doubler for every single iteration of for loop. I want it to fill the available spots in the array first and when it reaches the last element, then call array_doubler.
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot).
Actually they have undefined values in them. 0 is a valid value for them to have, but tomorrow the compiler might suddenly decide that they should all have 1 instead of 0.
If you want to detect the end of an array, then you have to remember how big the array is. C++ doesn't do it for you. Actually, it does do it for you if you use std::vector, but I suppose that's not the point of this exercise.
I'm not sure why you'd want to do this, as std::vector offer this kind of feature, and are more idiomatic of c++ (see isocpp faq on why C-style array are evil).
One of the issue of C-style array is the fact that they donĀ“t know their own size, and that they don't have default value, thus stay uninitialized.
If for some reason you need to not use std::vector, the next best solution would be to wrap the array with it's size in a structure or a class (which is kinda what std::vector is doing), or to initialize your array using std::memset (which is the C function you would use if you were in C).
Do keep in mind that this is not considered as good practices, and that the STL offer plenty of solution when you need containers.
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.
Im new to c++ and I dont know what this error means. It reads from a file and tries to store the values in a char * [].
The file contains:
5,Justin,19,123-45-6789,State Farm,9876,Jessica,Broken Hand,
This is my code.
void Hospital::readRecordsFile(){
std::ifstream fileStream;
fileStream.open(fileName); // Opens the file stream to read fileName
char * temp [8];
int i = 0;
while(!fileStream.eof()){
fileStream.get(temp[i],256,',');
i++;
}
i = 0;
for(char * t:temp){
std::cout << t << std::endl;
}
}
The error is at the line fileStream.get(temp[i],256,',');
You define an array of 8 pointers to char, but forget to allocate memory so that the pointers point to a valid chunk of memory:
char * temp [8]; // need then to allocate memory for the pointers
Because of this, in the line
fileStream.get(temp[i],256,',')
you end up using memory that's not yours.
Solution:
for(int i = 0; i<8; i++)
temp[i] = new char[256]; // we allocate 256 bytes for each pointer
Better though, use a std::vector<std::string> instead.
In the code you have right now it looks like you implicitly assume that the file has no more than 8 lines, which I find hard to believe. If your file has more than 8 lines, then you'll end up accessing the array of 8 pointers out of bounds, so you'll get another undefined behaviour (usually a segfault). That's why is much better to use standard STL containers like std::vector, to avoid all these headaches.
In case you MUST use pointers and want a variable number of lines, then you have to use a pointer to pointer,
char** temp;
then allocate memory for an enough pointers-to-char,
temp = new char* [1000]; // we believe we won't have more than 1000 lines
then, for each pointer-to-char, allocate memory
for(int i = 0; i < 1000; ++i)
temp[i] = new char[256];
At the end of the program, you must then delete[] in reverse order
for(int i = 0; i < 1000; ++i)
delete[] temp[i];
delete[] temp;
As you can see, it's getting messy.
You never allocated memory for each pointer in temp.
You probably want something like:
for (unsigned int i = 0u; i < 8; ++i)
{
temp[i] = new char[256];
}
The says that the temp variable points to 8 dynamically allocated byte buffers of 256 bytes each.
In C++, following the code below:
char *p = new char();
*p = 'a';
*(p+1)= 'b';
*(p+2) ='\0';
cout<<p<<endl;
we can get the output result: ab
When I want to write the code like this:
int *p = new int();
*p = 1;
*(p+1)= 2;
cout<<p<<endl;
It gives the result, but not 12 or something start with 12
Question is why the result goes wrong when changing it from char to integer? How to realize the goal that output a list of value by using a pointer dynamic array?
This is because char * is a bit of a special case.
In the C days, char * was the only type we really had to deal with strings. C++ makes it easier to interoperate with legacy code by providing streaming operators that treat char * values specially, by streaming out each character until a null character ('\0') is encountered.
When you stream out p when it's an int * there is no special case -- you just get the raw pointer value displayed.
If you want a one-liner to display the elements in a standard container, you can combine std::copy() with std::ostream_iterator:
std::copy(std::begin(some_array),
std::end(some_array),
std::ostream_iterator<int>(std::cout));
Since your array is allocated on the heap and stored in a pointer, std::begin() and std::end() won't work for you; you'll have to provide the end iterator manually:
std::copy(p, p + 2, std::ostream_iterator<int>(std::cout));
(See a demo.)
But note that both code samples in your question are undefined behavior, because you allocate a single object of type char or int and then try to assign beyond it. You write into memory you haven't allocated. Don't do this.
To fix your cases, you need to allocate enough room for the objects you intend to store:
// Case one
char *p = new char[3];
// Case two
int *p = new int[2];
And, of course, don't forget to delete[] p in both cases -- or you could just use std::string in the first case and std::vector<int> in the second.
Ok, first of all, this is unsafe:
*(p+1)= 'b';
You only allocated one byte and now you're stomping on memory you don't own - which is undefined behavior. If you want to allocate 3 bytes, do it:
char* p = new char[3];
Secondly, this:
int* pi = new int;
cout << pi << endl;
Will print the address of the pointer. char* is special in that cout will actually print the C-style string that is pointed to, but for other types - you just get the address.
If you want to print 12, you have to dereference the pointer:
int* pi = new int(12);
cout << *pi << endl;
If you want to output 1 and 2, separately, you need an array:
int* pi = new int[2];
pi[0] = 1;
pi[1] = 2;
cout << pi[0] << ", " << pi[1] << endl;
Note that, again, *(p + 1) = 2 in your code is stomping on memory you don't own.
I'm learning to use pointer to copy char array.
I have the following code in C++. What I'm trying to do is to transfer and array (set1) using pointer to another pointer array (temp).
But when I try to print out (temp), it is not the same as (set1).
Transfer an array via pointer to another temp array pointer.
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
char set1[] = "ABC";
char* p = &set1[0];
int tempSize = 0;
char* temp = new char[256];
for (int i = 0; i < 3; i++)
{
*temp = *p;
cout << *temp; // ABC
++temp;
++tempSize;
++p;
}
cout << "\n";
for (int i = 0; i < tempSize; i++)
{
cout << temp[i]; // Why ABC is not printed?
}
delete [] temp;
return 0;
}
// Why ABC is not printed?
Because your pointer is travelling in undefined behavior region:
char* temp = new char[256];
...
++temp; // gone !!
On top of that,
you are not terminating the string with \0 in the end (may not be needed in your code)
delete[]ing this corrupt pointer in the end.
Since you are writing for learning purpose, I would suggest simple fix to your code:
char* const temp = new char[256];
^^^^^ ensures `temp` is not modifiable
Now use temp[i] for traversing purpose.
It's because in the loop copying the array, you change temp. After the loop, it points to one beyond the copied data.
Also, you forget to terminate the new allocated array. You should add the character '\0' at the end.
The problem is this line:
++temp;
You are incrementing the pointer and then write to it. In the end temp[i]; does not point to the beginning of your string, but to the end.
The easiest way to do this is to remove the first for loop with:
for (int i = 0; i < 3; i++)
{
temp[i] = set1[i];
}
temp[4] = '\0'; // don't forget to close the string
C-style strings have a null terminator - "ABC" contains four characters. Also, I'm not at all sure that the delete call on temp is valid - you have been incrementing it since it was 'newed'.