Accessing dynamic 2D char array C++ - c++

In my class I've got:
private:
//...
char** mNumber;
//...
Then I initialize it in constructor:
PhoneBook::PhoneBook()
{
mNumber = NULL;
}
I also have method set default:
bool PhoneBook::setDefault()
{
lock();
//...
for (uint8 i = 0; i < 5; ++i)
{
mNumber[i] = new char[5];
for (uint8 k = 0; k < 4; ++k)
{
mNumber[i][k] = '0' + k;
}
mNumber[i][4] = '\0';
}
unlock();
return true;
}
In my program, when I want to write number (I can write up to five numbers), program should use method:
bool PhoneBook::write(DataOutputStream& s)
{
lock();
//...
unsigned long checksum = 0;
for (uint8 j = 0; j <5; j++)
{
unsigned short k = 0;
do
{
char number= mUserNo[j][k];
checksum += 0x000000FF & (number>> 8); //checksum is not problem here I guess
checksum += 0x000000FF & (number);
s.write_int8(userNo);
} while(mNumber[j][k++]=='\0');
}
s.write_uint32(checksum);
s.flush();
unlock();
return (s.ok());
}
It crashes at line:
char userNo = mUserNo[j][k];
It also do not set default values (they are not displayed in application window where they are supposed to be).
Visual Studio 2010 prompt:
Unhandled exception at 0x012b6fb8 (main_app.exe) in main_app: 0xC0000005: Access violation reading location 0xfdfdcdcd.
I've tried to debug it, but can't find out what's wrong. I can only guess that it's something wrong with 2d array, since I feel not so good with them and when I've tried something similiar with 1D, it worked fine.
Please help me with code and let better understand multiD arrays in c++.
BTW I'm not allowe to use std::string. Just no, I can't use it here.

You only ever set mNumber to NULL so any access to memory via mNumber, mNumber [j][k] for example, is most likely going to crash with an access violation (1). You need to initialise mNumber to be a meaningful value, by using new somewhere! Better still, use a standard container like std::vector:
// the declaration of mNumber, do not initialise mNumber to NULL!
std::vector <char *> mNumber; // only need one * here!
(1) This is the most common thing to happen on Windows and Linux, some (but not many) OSes/systems may silently let you do this!

if you need "char**" instead std::vector, you should to allocate memory for it before filling default values. Like this,
bool PhoneBook::setDefault()
{
........
mNumber = new char*[5]; // allocating memory for mNumber
for (uint8 i = 0; i < 5; ++i)
{
mNumber[i] = new char[4];
for (uint8 k = 0; k < 4; ++k)
{
mNumber[i][k] = '0' + k;
}
mNumber[i][4] = '\0';
}
unlock();
return true;
}

Related

Allocating pointer to a pointer

I have 5 buffers and 20 frames to write in them. Being one frame per buffer, at a certain moment i will have to overwrite buffers with the newest frame.
At random moments i need to read the oldest frame(its id and data) from all the buffers.
I am obliged to use a pointer to a pointer for my buffers, but since i suck at pointers, not even the allocation works, giving me a SEGMENTATION FAULT and not sure why.
What i have until now:
void fakeFrame(uint16_t *data)
{
for (auto i = 0; i < 1440; i++)
for (auto j = 0; j < 1440; j++)
data[(i * 1440) + j] = std::rand()%2;
}
int main()
{
uint16_t **p_frameBuffers;
uint32_t *p_frameIdxs;
uint16_t wrIdx = 0;
uint16_t reIdx = 0;
uint16_t currentFrameCounter = 0;
uint16_t nbBuffers = 5;
for(auto i =0; i< nbBuffers; i++)
{
p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2);
}
while(currentFrameCounter <= 20)
{
wrIdx++;
wrIdx %= nbBuffers;
if(wrIdx == reIdx)
{
std::cout<<"i passed the limit";
}
currentFrameCounter++;
p_frameIdxs[wrIdx] = currentFrameCounter;
fakeFrame(p_frameBuffers[wrIdx]);
}
std::cout<<"\n";
return 0;
}
I can see a few different problems with this code here.
You declare the long-form of the function for fakeFrame() in the beginning of the program, when the standard is usually to declare the function header first.
This is like a warning to the program that a function is about to be used, and that it's not part of a class or anything. Just standalone.
Example:
#include <iostream>
void fakeFrame();
int main()
{
return 0;
}
void fakeFrame()
{
for (auto i = 0; i < 1440; i++)
for (auto j = 0; j < 1440; j++)
data[(i * 1440) + j] = std::rand()%2;
}
You're also using some of these 16 and 32 bit unsigned ints as if they were arrays, so I was deeply confused about that. Did you mean to set them as arrays?
You also have some variables being declared in a non-array context but being used as arrays. I'm not deeply familiar with the uint variable/object types but I know they aren't usually meant to function as standalone arrays.
Also, no variable called m_pFrameBuffers is actually declared in the code you provided. Plus this is also used as an array, so it should really be declared as one.
I hope this provides at least some insight into what's not working. I'm actually kind of surprised that the void function ran before, it's improperly formatted.
In the end this is what did it: the pointer to a pointer is actually an array of pointers (which i did not know, of course)
p_frameBuffers = (uint16_t**)malloc((sizeof(uint16_t*)*nbBuffers));
for(auto i = 0; i < nbBuffers; i++)
{
p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2);
}

The array in my singleton isn't keeping information after leaving a function and then it crashes when it tries to access the information again

I have an array called int **grid that is set up in Amazon::initGrid() and is made to be a [16][16] grid with new. I set every array value to 0 and then set [2][2] to 32. Now when I leave initGrid() and come back in getGrid() it has lost its value and is now 0x0000.
I don't know what to try, the solution seems to be really simple, but I'm just not getting it. Somehow the data isn't being kept in g_amazon but I could post the code.
// Returns a pointer to grid
int** Amazon::getGridVal()
{
char buf[100];
sprintf_s(buf, "Hello %d\n", grid[2][2]);
return grid;
}
int Amazon::initGrid()
{
int** grid = 0;
grid = new int* [16];
for (int i = 0; i < 16; i++)
{
grid[i] = new int[16];
for (int j = 0; j < 16; j++)
{
grid[i][j] = 0;
}
}
grid[2][2] = 32;
return 0;
}
int **grid;
g_amazon = Amazon::getInstance();
g_amazon->initGrid();
grid = g_amazon->getGridVal();
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
int index;
index = (width * 4 * i) + (4 * j);
int gridval;
gridval = grid[i][j];
lpBits[index] = gridval;
lpBits[index + 1] = gridval;
lpBits[index + 2] = gridval;
}
}
It crashes when I run it at the line where sprintf_s prints out [2][2] and it also crashes when I get to gridval = grid[i][j] because it's at memory location 0x000000.
The variable
int** grid
in the initGrid() function is a local variable. Edit** When the function returns the variable is popped off the stack. However, since it was declared with the new operator the memory still exists on the heap; it is simply just not pointed to by your global grid variable.
#Dean said in comment:
I have grid as an int** grid; in class Amazon {}; so shouldn't it stay in memory or do I need a static var.
That is the problem:
local int **grid; on Amazon::initGrid::
is masking
member int **grid; on Amazon::
as the first context has higher priority in name lookup.
So initGrid() allocates memory referenced only by a local pointer. That pointer no longer exists when you return from this function, Amazon::grid was never touched on initialization and you're also left with some bad memory issues.
So, as commented by #Remy-Lebeau, I also suggest
Consider using std::vector> or std::array, 16> instead. There is no good reason to use new[] manually in this situation.

Having trouble understanding what caused this segmentation fault (C-style strings in C++)

This problem comes from a textbook: Programming -- Principles and Practice Using C++ (Second Edition) By Bjarne Stroustrup.
Note: I have solved the problem, the question comes from my lack of understanding as to how my earlier attempts at a solution failed. I know it is a long question but I feel that it is important to understand this concept.
Here is the problem:
Write a function, char* findx(const char* s, const char* x), that finds the first occurrence of a C-style string x in s.
I could easily have looked up the solution (or alter the way the function is declared) but if I feel like this issue is the whole point of the exercise, so I held off on that. Feel free to correct any wrong statements I make in this question. Also, forgive me if this is an over complication but I really don't understand this.
For starters, here is my function written in a way that compiles, but causes a segfault at runtime:
char* findx(const char* s, const char* x) {
if (s==nullptr || x == nullptr) return nullptr; //if no string, return nullptr
int s_size = strlen(s);
int x_size = strlen(x);
char* ptr_to_first_occ = nullptr; //initialize pointer to 1st occ
for (int i = 0; i < (s_size-x_size); ++i) { //end with the last char that
//can hold string x to the end
for (int j = i; j < x_size; ++j) { //check if the first char match
if (s[j] != x[j]) ptr_to_first_occ = nullptr; //if it doesn't, set to 0
//and move on
else ptr_to_first_occ = (char*)(s) + i; //set equal to first occ if ==
}
}
if (ptr_to_first_occ) return ptr_to_first_occ;
else return nullptr;
}
Here is main:
const char* y = "Hey how are you?";
const char* t = "you";
char* p = nullptr;
p = findx(y, t);
cout << *p << endl;
The only reason this compiles is due to the fact that I cast the const char s to char*, which is not the right way to do things, but I am pretty sure the segfault is not caused by this as my solution includes the cast.
My goal here is to return a pointer to the memory location that holds the first character of string x in string s. The problem is that the first character itself is contained within a string that is passed as const in the first place, so the pointer to it is of type const char , not char as is the pointer that I declare. If I want to declare ptr_to_first_occ as a const char*, I can no longer assign the proper location to it since it is not writeable. This leaves me to either completely change the function (I am expected to return a char*, I could probably do it another way rather quickly) or to use a cast. Or I can change that part as such:
for (int i = 0; i < (s_size-x_size); ++i) {
for (int j = i; j < x_size; ++j) {
if (s[j] != x[j]) ptr_to_first_occ = nullptr;
else {
const char* ptr_to_first_occ = &s[i];
}
}
}
Problem is that the declaration makes it so that this variable only exists within the scope of that else, and I can't use a dummy variable to store that const char* before the the pointer goes out of scope, because I can't assign to const variables that were declared before.
At this point I realize that this:
for (int j = i; j < x_size; ++j) {...}
makes no sense, and should actually be:
for (int j = i; j < i + x_size; ++j) {...}
Alright, fair enough. My function is now this:
char* findx(const char* s, const char* x) {
if (s==nullptr || x == nullptr) return nullptr;
int s_size = strlen(s);
int x_size = strlen(x);
char* ptr_to_first_occ = nullptr;
for (int i = 0; i < (s_size-x_size); ++i) {
for (int j = i; j < i+x_size; ++j) {
if (s[j] != x[j]) ptr_to_first_occ = nullptr;
else {
ptr_to_first_occ = (char*)&s[i];
}
}
}
if (ptr_to_first_occ) return ptr_to_first_occ;
else return nullptr;
}
Compiles, and logically seems to work, but I still get a segfault due to the same reason I suspect (Segmentation fault: 11). I now change main to this:
const char* y = "Hey how are you?";
const char* t = "you";
char* p = nullptr;
p = findx(y, t);
if (p) cout << *p << endl;
Turns out that this prints nothing, so p must have remained a nullptr. Anyway, after many debugging flags, and a bunch of trial and error (read: rewriting the function in a way that made it look like a dumpster) I cleaned up the whole thing, and managed to solve the problem:
char* findx(const char* s, const char* x) {
if (s==nullptr || x == nullptr) return nullptr;
int s_size = strlen(s);
int x_size = strlen(x);
char* ptr_to_first_occ = nullptr;
for (int i = 0; i < (s_size-x_size); ++i) {
if (s[i] != x[0]) ptr_to_first_occ = nullptr;
else {
for (int k = 0; k < x_size; ++k) {
if (s[i+k] == x[k]) ptr_to_first_occ = (char*)&s[i];
else {
ptr_to_first_occ = nullptr;
break;
}
}
}
}
if (ptr_to_first_occ) return ptr_to_first_occ;
else {
return nullptr;
}
}
Which means that the cast had nothing to do with the segmentation fault, and this is essentially where my question comes from. I simply could not track down the reason for the fault in my earlier code. I would like some input as to how to understand the cause of a segmentation fault as it relates to memory locations, since my understanding of how the read only memory locations work was wrong. What was I trying to do that caused my error?

C++ pointer to int in loops?

Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &

Deleting pointers from an array

I am fairly new to C++, and this problem I am having has had me stumped for like the last 2 hours. What I am trying to do is create an array of pointers to my class Word objects, so a 2 dimensional array, which is **wordPtrList. Then I need to delete the memory of certain objects in the array and set their pointers to null. I have written a smaller version of what I am trying to accomplish below.
int main()
{
char *cArray;
cArray = new char[4];
int i;
for (i = 0; i < 3; i++)
cArray[i] = 'a';
cArray[i + 1] = '\0'; //cArray is a null terminated string
Word **wordPtrList;
wordPtrList = new Word* [3];
for (i = 0; i < 3; i++)
{
wordPtrList[i] = new Word(cArray);
}
wordPtrList[1]->del();
delete wordPtrList[1];
wordPtrList[1] = '\0';
return 0;
}
class Word
{
private:
char* ptr_;
int len_;
public:
Word(const char* word)
{
len_ = strlen(word);
ptr_ = new char[len_];
strcpy(ptr_, word);
}
~Word()
{
delete [] ptr_;
ptr_ = 0;
}
void del()
{
delete [] ptr_;
ptr_ = 0;
return;
}
};
When I do this however, I get:
Debug Error Heap Corruption Detected after normal block
This is in VS 2010 on Windows 7.
So what I am asking is, how do I delete the memory of my object so that I can set wordPtrList[1] to Null?
You are allocating 4 bytes to cArray (meaning you have access to write to bytes 0 through 3), and then writing to cArray[4]. You also allocate one byte too small in the Word constructor.
char *cArray;
cArray = new char[4];
int i;
for (i = 0; i < 3; i++)
cArray[i] = 'a';
cArray[i] = '\0'; //cArray is a null terminated string - i is now 3
and
Word(const char* word)
{
len_ = strlen(word);
ptr_ = new char[len_ + 1];
strcpy(ptr_, word);
}
should do the trick.
Look at this code:
for (i = 0; i < 3; i++)
cArray[i] = 'a';
cArray[i + 1] = '\0'; //cArray is a null terminated string
The problem is at the last line which is using i+1 as index, which is going out of range, as by the time the loop exits, the value of i is already 3; that means i+1 will become 4 which cannot be a valid index when you've allocated cArray as:
cArray = new char[4]; //taken from your code
The solution is this:
cArray[i] = '\0'; //Now, it is correct. Here i is equal to 3
That is, use i instead of i+1; Or simply use 3.
In C++, you could std::fill instead of manual loop, as:
std::fill(cArray, cArray + 4, 'a'); //done
Even better avoid using char* with new as much as possible, and prefer using std::string instead.
There are two obvious off-by-one errors in the code (when you get out of the first loop what is the value of the variable i? when calling strlen did you remember to consider the space needed by the null terminator?).
Also please note that c strings are not "null terminated", they are "NUL terminated" with uppercase letters and only one "L". NUL is the name of the ASCII control character with all bits set to zero and is represented in C++ with '\0'.
In one place you used NUL character as a null pointer, and while this is technically correct (because of a design bug of the C++ language) it's better to understand that the two concepts are quite different.
As others have said, you're basically accessing an array index which is out of bounds of the array.
I would go with Nathan Wiebe's solution.
In the future, when you have the option to do this, it's recommended to use std::vector<T> as that will allow you to store any type you wish in a dynamically resizeble array. In other words, providing you don't access an index which is outside of the vector's bounds, you could do something like this:
std::vector< char* > str;
for( size_t i = 0; i < str.size(); ++i )
{
str.push_back( 'a pointer to a block of memory consisting of characters' );
}
class Word
{
public:
Word( const char* str )
{
mStrs.push_back( str );
}
~Word( void )
{
for( size_t i = 0; i < mStrs.size(); ++i )
{
if( mStrs[ i ] )
{
delete mStrs[ i ];
mStrs[ i ] = NULL;
}
}
mStrs.clear();
}
private:
void del( size_t index )
{
if( index > mStrs.size() )
{
//error - throw new exception or something
}
delete mStrs[ index ];
}
std::vector< const char* > mStrs;
};