I've searched through many articles on here and have self-tested this concept with my own code. My question is to satisfy my own curiosity and maybe help others as I cannot find a answer describing this concept in particular. My textbook (teaching C++) describes a C-string variable:
A C-string variable is an array of characters. The following array declaration provides a C-string variable "s" capable of storing a
C-string value with nine or fewer characters:
char s[10];
The 10 is for the nine letters in the string plus the null character '\0' to mark the end of the string. Like any other partially filled
array, a C-string variable uses positions starting at indexed variable
0 through as many as are needed.
I'm trying to understand the above. If the array size is 10, wouldn't the total storage size be 11? i.e. 0-10 = 11 spaces. If the \0 character occupies one space, then we'd still be able to store 10 characters and not 9 as per the book.
In my own testing, I declared a character array test[4] and stored the word "cat" in the array. When looking at individual positions within the array, I can see individual characters at each index i.e:
test[0] = c
test[1] = a
test[2] = t
test[3] =
test[4] =
Why do we need 2 additional slots in the character array and not 1?
An array with size N has indexes starting at 0 and ending with N-1. It does not have an element with index N.
With your example of char test[4], the array has indexes 0, 1, 2, and 3. Attempting to access index 4 is going off the end of the array. C and C++ do no prevent you from doing so, and attempting to do so invokes undefined behavior.
You can look at an array as a group of variables of the same type and size which are consecutive in memory one next to the other.
Arrays are indexed from 0 as the first element to the n - 1 as the last element. So you can access any element just using an index.
Trying to access an array with an index i >= n or a negative index i < 0 Will issue in undefined behavior.
Arrays of characters need to set the last element as a NULL character \0.
Here is an example:
char c[5] = "Hello"; // Error
Above c has 5 elements and \0 so it is 6 Byte long. So to correct it:
char c[6] = "Hello"; // Null character added automatically
// char c[] = "Hello";
Look at this example:
char text[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
Above in a such initialization you must add the null terminator character '\0' otherwise you'll get a garbage characters at the end of your string.
std::cout << text[0]; // H which is the first element
std::cout << text[6 - 1 - 1]; // o which is the last character in the array.
arrays of other types other than characters need not to add a null terminator and the number of elements is n but indexing is the same 0 through n - 1;
int array[5] = {4, 5, 9, 22, 16};
std::cout << array[0]; // 4
std::cout << array[5 - 1]; // 16
I think your problem comes from the misconception of how you access the memory.
s[n] refers at accessing the value pointed by the pointer s plus n blocks in memory, it can also be written *(s + n)
So basically, declaring
char s[4];
and setting cat in it, you will get this layout in memory
+---+
s: | c | s[0] also (s + 0)
+---+
| a | s[1] also (s + 1)
+---+
| t | s[2] also (s + 2)
+---+
|\0 | s[3] also (s + 3)
+---+
| ? | s[4] also (s + 4)
+---+
| ? | s[5] also (s + 5)
+---+
| ? | s[6] also (s + 6)
+---+
| ? | s[7] also (s + 7)
+---+
| ? | s[8] also (s + 8)
+---+
| ? | s[9] also (s + 9)
+---+
The ? stand for a variable which we aren't sure of the value.
You CAN access it, you can even modify it sometimes.
But the behavior of this isn't clear and can be undefined.
For your example s[4] can change each time the executable is executed.
char s[10]; had valid indices from 0 to 9 and not 0 to 10 as you said.
A C-string variable is an array of characters.
This is slightly misleading. A C string is a sequence of character values followed by a 0-valued terminator. For example, the string "Hello" is represented as the sequence {'H','e', 'l', 'l', 'o', 0}. The presence of the 0 terminator makes the character sequence a string. All C string handling functions (strcat, strcmp, strcpy, strchr, etc.) assume the presence of that terminator; if the terminator isn't there, those routines will not function properly.
Strings are stored in arrays of character type (char for ASCII, EBCDIC, or UTF-8 strings or wchar_t for "wide" strings1). Multiple strings may be stored in a single array if there's sufficient space. A 10-element array may store a single 9-character string, or two 4 character strings, or 5 one-character strings. Remember that to store an N-character string you need N+1 array elements to account for the terminator.
I'm trying to understand the above. If the array size is 10, wouldn't the total storage size be 11? i.e. 0-10 = 11 spaces.
Total storage size is 10, but array elements are indexed from 0 to 9. Given the declaration
char foo[10];
you get the following layout in memory:
+---+
foo: | | foo[0]
+---+
| | foo[1]
+---+
| | foo[2]
+---+
| | foo[3]
+---+
| | foo[4]
+---+
| | foo[5]
+---+
| | foo[6]
+---+
| | foo[7]
+---+
| | foo[8]
+---+
| | foo[9]
+---+
For any N-element array, individual elements are indexed from 0 through N-1.
Remember that in C, the array subscript operation a[i] is defined as *(a + i) - given a starting address a2, offset i elements (not bytes!!!) from that address and dereference the result. The first element is stored at a, the second element is stored at a + 1, the third at a + 2, etc.
wchar_t was introduced to represent character sets outside the ranges defined by ASCII or EBCDIC, so it's wider than the `char` type (often the width of two `char`s). With the advent of schemes like UTF-8 to represent non-English character sets, it's not that useful and I don't see it used very often.
At some point, you're going to hear someone say "an array is just a pointer". This is not correct. Under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array. The array object itself is not a pointer, nor does it set aside any space for a pointer value.
char test[4] is the definition of your array, it means your array's size is four, but you can only use the spaces: test[0], test[1], test[2], test[3].
You can go to http://www.cplusplus.com/doc/tutorial/arrays/ to learn more about Arrays of c++.
Related
Activity solution[a][b];
...
Activity **mother = solution;
I want to convert 2D array of objects to pointer-to-pointer. How can I do this;
I searched it on google. however I found only one dimension array example.
A mere conversion won't help you here. There's no compatibility of any kind between 2D array type and pointer-to-pointer type. Such conversion would make no sense.
If you really really need to do that, you have to introduce an extra intermediate "row index" array, which will bridge the gap between 2D array semantics and pointer-to-pointer semantics
Activity solution[a][b];
Activity *solution_rows[a] = { solution[0], solution[1] /* and so on */ };
Activity **mother = solution_rows;
Now accessing mother[i][j] will give you access to solution[i][j].
The reason you can do this for one-dimensional arrays and not two-dimensional arrays has to do with the way in which the actual array elements are stored in memory. For one-dimensional arrays, all of the elements are stored consecutively, so the expression array[i] is equivalent to the expression *(array + i). As you can see, the array size is not needed to perform an array index operation. However, for two-dimensional arrays, the elements are stored in "row major" order, meaning that all of the elements in the zeroth row are stored first, followed by the elements in the first row, followed by the elements in the second row, etc. Therefore, the expression array[i][j] is equivalent to *(array + (i * ROW_SIZE) + j), where ROW_SIZE is the number of elements in each row. Therefore, the array's row size is needed to perform an array index operation, and casting the array variable to a pointer loses that information.
This is c++! Everything is possible! But a this is c++ so it requires some level of understanding.
To that end let's start with a simple example of 2 1-dimensional arrays: char firstName[4] = { 'J', 'o', 'n', '\0' } and char lastName[4] = { 'M', 'e', 'e', '\0' } Let's look at a possible memory layout here:
+------------+-------+
| Address | Value |
+------------+-------+
| 0x76543210 | 0x4A | <- firstName[0] - 'J'
| 0x76543211 | 0x6F | <- firstName[1] - 'o'
| 0x76543212 | 0x6E | <- firstName[2] - 'n'
| 0x76543213 | 0x00 | <- firstName[3] - '\0'
+------------+-------+
| 0x76543214 | 0x4D | <- lastName[0] - 'M'
| 0x76543215 | 0x65 | <- lastName[1] - 'e'
| 0x76543216 | 0x65 | <- lastName[2] - 'e'
| 0x76543217 | 0x00 | <- lastName[3] - '\0'
+------------+-------+
Given this memory layout if you were to do cout << firstName << ' ' << lastName you'd get:
0x76543210 0x76543214
These arrays are really just a pointer to their first element! This illustrates Array to Pointer Decay, which you can read more about here: http://en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay
Before we move on there's something important here to note, chars take up exactly 1-byte so the address of each subsequent char in the array will simply be the next address. That's leveraged by the Subscript Operator in this way: firstName[1] is equivalent to *(firstName + 1). This is true for chars but is also true for any other type which takes up more than 1-byte. Let's take for example: short siArray = { 1, 2, 3, 4 }, a possible memory layout of siArray would look like:
+------------+--------+
| Address | Value |
+------------+--------+
| 0x76543218 | 0x0001 | <- siArray[0] - 1
| 0x7654321A | 0x0002 | <- siArray[1] - 2
| 0x7654321C | 0x0003 | <- siArray[2] - 3
| 0x7654321E | 0x0004 | <- siArray[3] - 4
+------------+--------+
Even though cout << siArray << ' ' << &(siArray[1]) will output:
0x76543218 0x7654321A
*(siArray + 1) will still index the same element of siArray as siArray[1]. This is because when doing pointer arithmetic c++ considers the type of the address being operated on, thus incrementing a short* will actually increase the address by sizeof(short). You can read more about pointer arithmetic here: http://en.cppreference.com/w/cpp/language/operator_arithmetic
Lastly let's look at how c++ stores 2-dimensional arrays. Given: char name[2][4] = { { 'J', 'o', 'n', '\0' }, { 'M', 'e', 'e', '\0' } } a possible memory layout would be:
+------------+-------+
| Address | Value |
+------------+-------+
| 0x76543220 | 0x4A | <- name[0][0] - 'J'
| 0x76543221 | 0x6F | <- name[0][1] - 'o'
| 0x76543222 | 0x6E | <- name[0][2] - 'n'
| 0x76543223 | 0x00 | <- name[0][3] - '\0'
| 0x76543224 | 0x4D | <- name[1][0] - 'M'
| 0x76543225 | 0x65 | <- name[1][1] - 'e'
| 0x76543226 | 0x65 | <- name[1][2] - 'e'
| 0x76543227 | 0x00 | <- name[1][3] - '\0'
+------------+-------+
Since we know an 1-dimensional array value is really just a pointer, we can see from this memory layout that name[0] is not a pointer, it's just the first character of the first array. Thus name does not contain 2 1-dimensional array pointers, but contains the contents of the 2 arrays. (Incidentally on a 32-bit machine not storing the pointers saves 8-bytes of memory, which is pretty substantial for an 8-byte 2-dimensional array.) Thus trying to treat name as a char** would try to use the characters as a pointer.
Having understood this we really just need to avoid using c++'s pointer arithmetic to find dereference the value. To do that we'll need to work with a char* so that adding 1 is really just adding 1. So for example:
const short si2DArray[2][3] = { { 11, 12, 13 }, { 21, 22, 23 } };
const auto psi2DPointer = reinterpret_cast<const char*>(si2DArray);
for(auto i = 0U; i < size(si2DArray); ++i) {
for(auto j = 0U; j < size(*si2DArray); ++j) {
cout << *reinterpret_cast<const short*>(psi2DPointer + i * sizeof(*si2DArray) + j * sizeof(**si2DArray)) << '\t';
}
cout << endl;
}
Live Example
Note that in this example even though I reference si2DArray thought psi2DPointer I'm still using information from si2DArray to do the indexing, namely:
How many arrays are in the major dimension: size(si2DArray)
How many elements are in the minor dimension: size(*si2DArray)
What is the size in memory of the minor dimension: sizeof(*si2DArray)
What is the element type of the array: sizeof(**si2DArray)
You can thus see that the loss of information from converting from an array to a pointer is substantial. You may be tempted to preserve the element type, thereby also simplifying the pointer arithmetic. It's worthwhile to note that only a conversion to char* is considered defined behavior by reinterpret_cast: http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing
I want to convert 2D array of objects to pointer-to-pointer. How can I do this?
Why? Is it because an interface expects a pointer to pointers?
If so, you'll need to create a new array that contains those pointers.
Activity solution[a][b];
Activity* solutionPtrs[a];
for (int i = 0; i < a; ++i)
solutionPtrs[a] = solution[a];
Activity** mother = solutionPtrs;
Why can't you just cast a 2D array of T to T**? Well, because they have nothing to do with one another!
You can cast a T[a] to a T* because you get a pointer to the first element of the array.
You can do this with 2D arrays as well, but if you have a T[a][b] then it decays to a (T[b])* because a 2D array is not an array of pointers, it's an array of arrays.
Not sure if you were looking for something like this. You should provide more details about what you want to achieve. They are fundamentally different types. One solution is to below.
For the record, if someone finds it useful:
// define matrix
double A[3][3] = {
{ 1, 2, 3},
{ 4, 5, 6},
{ 7, 8, 9}
};
// allocate memory
double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
for (int i = 0; i < 3; i++)
A_ptr[i] = (double *) malloc(sizeof (double) * 3);
// copy matrix
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
A_ptr[i][j] = A[i][j];
printf(" %f ", A_ptr[i][j]);
}
}
You can't. They are fundamentally different types.
I was wondering if anyone can tell me the difference between two expressions:
*(ptr+i) and *ptr+i
It is used in the code as follows:
char string[]="hello";
char *ptr;
ptr=string;
for(int i=0;string[i]!='\0';i++)
{
cout<<*(ptr+i); //*ptr+i
}
Let's say you have an array of 3 integers, with values 150, 200, and 250. In memory, this array would look like:
+----------+----------+----------+---
| 96000000 | c8000000 | fa000000 |...
+----------+----------+----------+---
| aka 150 | aka 200 | aka 250 |...
+----------+----------+----------+---
a (a+1) (a+2)
Now, you're not dealing with an array of integers here, but integers are somewhat easier to demonstrate.
Pointers and arrays are largely interchangeable in C/C++, so in the above example, think of a as a pointer. Already this means that string and ptr are essentially the same variable.
With that said, the difference between *(pointer+i) and *pointer+1 is what the 1 is applied to. In the first case, it is the pointer's address. In the second case, it is the value the pointer points to. To continue with the above example:
int x = *a+1; // x is 151
int y = *(a+1); // y is 200
int z = *(a+1)+1; // z is 201
Okay so I have:
char* arr[5];
and I have
char input[10];
and then:
int i = 0;
cin.getline(input, 10);
while(input[0] != 'z')
{
arr[i] = input;
cin.getline(input, 10);
i++;
}
the result is that every element in arr is the same because they are all pointers to input, but I want each element to point to char arrays that the input variable held at that given time.
result that this brings:
arr[0] = line beginning in 'z' (because that is what input currently is holding)
arr[1] = line beginning in 'z'
arr[2] = ... and so on
result that I want:
arr[0] = first line read in
arr[1] = second line read in
arr[2] = third line read in and so on...
I am confused about how I can get the elements to all point to new values instead of all be pointing to the same value.
If you want to take input 5 times,you can try this code segment
int i = 0;
while(i<5)
{
arr[i] = input;
cin.getline(input, 10);
i++;
}
this should work and you can get your "desired result" as you stated above.
Edit:
This will not work, as described in the comment. See example here: http://ideone.com/hUQGa7
What is required are different pointer values occupying each of the elements in arr. How to achieve those different pointer values is discussed in the other answers given.
Let's talk characters and pointers.
Given a character:
+---+
+ A +
+---+
A pointer to the character, char *, points to the character. That's it, nothing more.
An array of characters is a container that has slots for characters. A pointer to the array often points to the first character of the array. Here's where the problem comes in.
Many functions require a pointer, to the first character of the array, but either don't say that it's to the first character or require a pointer to a single character, assuming that the pointer is the first character in the array.
Pointers need something to Point at
You have allocated an array of pointers, but haven't allocated the memory for each pointer:
Array
+-----+ +----+---+---+
| | --> | | | |
| | +----+---+---+
+-----+
| | +----+---+---+
| | --> | | | |
| | +----+---+---+
+-----+
The content of the array are pointer. So you will need to allocate memory and place the pointer into the array:
arr[0] = new char [11]; // +1 for the nul terminator character.
char text[33];
arr[1] = text;
So what you aim to do is:
cin.getline(arr[0], 10);
cin.getline(arr[1], 33);
Strings are soooo much easier to deal with. They manage their own memory:
std::string array_text[5]; // An array of 5 string.
getline(cin, array_text[0]);
The next step is to use a vector and you are all caught up:
std::vector< std::string > text_vector(5); // Pre-allocate 5 slots.
getline(cin.text_vector[2]);
You have to copy the data of input everytime.
You can do like this in while loop:
while(input[0] != 'z')
{
arr[i] = new char[strlen(input)];
strcpy(arr[i], input);
cin.getline(input, 10);
i++;
}
And since you have defined arr to be of length 5. So you have to check in the while loop that i doesn't exceed the value 5. i<5.
/* what i observed is :
when i give string like "ab" to b(array)
then the output is : "ab" "help" "dude"
when i give "abc"
then output is : "abc" " " "dude"
if i give "abcd"
then output is : "abc" "d" "dude"
so on */
#include<stdio.h>
main()
{
char a[5]="help",b[3],c[10]="dude";
scanf("%s",b);
printf("\t%s",b);
printf("\t%s",a);
printf("\t%s",c);
}
/* what i dont get is :
Here iam gaving a string to b(array), why, if the string has more than the
required no. of charecters, its printing those charecters in other arrays
(though i had not assiged scanf to other arrays )?
Remember that a string in C needs space for a null terminator. If there is no space, printing will continue "to the next nul". Here is how your memory looks at initialization:
h e l p \0 \0 \0 \0 d u d e \0
^ ^ ^
a b c
When you read in a string ab in the location pointed to by b:
h e l p \0 a b \0 d u d e \0
^ ^ ^
a b c
And all is well. But abc gives:
h e l p \0 a b c \0 u d e \0
^ ^ ^
a b c
and when you print b you will get abc; printing c will get you nothing (first character is '\0').
Finally, with an input of abcd you get
h e l p \0 a b c d \0 d e \0
^ ^ ^
a b c
And printing c will result in "d" - exactly as you are seeing.
In fact, the order in which things are stored in memory is not "defined", although usually the compiler will do something similar to the above. So while you know that you can't write to memory that isn't yours, you can't be sure what will happen when you do (as in your case). That is why it is called "undefined behavior". You can't rely on other compilers giving you the same result - or even the same compiler giving you the same result...
Make sense?
The solution, of course, is to allocate more space to b. That would result in more '\0' between b and c, and nothing gets overwritten.
edit - I did just realize that it seems that the order in which b and a are stored is backwards from how I just described it - because it's a, not c that is getting overwritten. Which shows that the compiler orders things as it jolly well pleases, and that I ought to wear my glasses when I write detailed answers. But the principle is exactly the same - so I will "leave the rest as an exercise for the student".
Your arrays are placed in memory in the following order
c[10], b[3], a[5]
So if array b will contain more characters than it can accomodate then some its characters will overlap array a,
Consider these two arrays, b and a, as they are in memory
b[0] b[1] b[2] a[0] a[1] a[2] a[3] a[4]
When you eneters "abc" in b you got
b[0] b[1] b[2] a[0] a[1] a[2] a[3] a[4]
'a' 'b' 'c' '\0' 'e' 'l' 'p' '\0'
So after executing the statements
printf("\t%s",b);
printf("\t%s",a);
the output is
"abc" ""
because a[0] contains '\0'
When you entered "abcd" you got
b[0] b[1] b[2] a[0] a[1] a[2] a[3] a[4]
'a' 'b' 'c' 'd' '\0' 'l' 'p' '\0'
and the output is
"abcd" "d"
because a[0] contains 'd' and a[1] contains '\0'
b[3] is an array of 3 characters. However the string abc is made of 4 characters, the last one being \0, indicating end of the string. So if you want be to be able to store abc, you need to declare at least an array of 4 characters, not 3
when you give abc as input your array b gets filled up(as it has only 3 places ) and has no space left for \0character. As a result when you try to print it out as a string .. it overflows and causes the error
For a string to be printable, it has to be of the following format:
stringtext\0 but when you use up all the spaces in your array b you leave no space for \0 as a result when you print it , there is error
Also this statement is wrong in your code :
scanf("%s",&b);
it should be :
scanf("%s",b);
So what's really happening is you are going outside the end of your arrays and overwriting memory.
When you provide 'ab' as input to b, it works because b is large enough to store 'ab' and the \0 as others have mentioned.
When you provided 'abc' as input, b does not have enough space allocated to store abc and the null so it only stores 'abc' and then the null appears to get written to the first byte of the a array, which means it's just an empty string... or maybe it doesn't, this is the undefined part. Who knows what is stored outside your array. It just so happens you are probably getting lucky since those arrays you have defined are most likely in contiguous memory.
When you provide 'abcd' as input, the d and the null get written to the a array.
Many times in less-simple programs, you'll get a SEGV with programming errors like this.
This is simply one of the case of undefined behavior. b[3] can store a string of three characters (including \0), but when your input is abc it is of four character string and you can't store it in array b. You will get anything.
When you place "abc" into b[3], it's going past the end of the array. The abc string is four bytes since it has a nul terminator at the end.
Since it's undefined behaviour, anything can technically happen but what's actually happening is that the nul at the end of the string is overwriting the first character of the next variable in memory, rendering it an empty string.
Quickest solution is to ensure your character array are big enough to store all the characters plus the terminator:
char b[4] = "abc";
Or let the compiler handle it for this particular simple case:
char b[] = "abc";
Activity solution[a][b];
...
Activity **mother = solution;
I want to convert 2D array of objects to pointer-to-pointer. How can I do this;
I searched it on google. however I found only one dimension array example.
A mere conversion won't help you here. There's no compatibility of any kind between 2D array type and pointer-to-pointer type. Such conversion would make no sense.
If you really really need to do that, you have to introduce an extra intermediate "row index" array, which will bridge the gap between 2D array semantics and pointer-to-pointer semantics
Activity solution[a][b];
Activity *solution_rows[a] = { solution[0], solution[1] /* and so on */ };
Activity **mother = solution_rows;
Now accessing mother[i][j] will give you access to solution[i][j].
The reason you can do this for one-dimensional arrays and not two-dimensional arrays has to do with the way in which the actual array elements are stored in memory. For one-dimensional arrays, all of the elements are stored consecutively, so the expression array[i] is equivalent to the expression *(array + i). As you can see, the array size is not needed to perform an array index operation. However, for two-dimensional arrays, the elements are stored in "row major" order, meaning that all of the elements in the zeroth row are stored first, followed by the elements in the first row, followed by the elements in the second row, etc. Therefore, the expression array[i][j] is equivalent to *(array + (i * ROW_SIZE) + j), where ROW_SIZE is the number of elements in each row. Therefore, the array's row size is needed to perform an array index operation, and casting the array variable to a pointer loses that information.
This is c++! Everything is possible! But a this is c++ so it requires some level of understanding.
To that end let's start with a simple example of 2 1-dimensional arrays: char firstName[4] = { 'J', 'o', 'n', '\0' } and char lastName[4] = { 'M', 'e', 'e', '\0' } Let's look at a possible memory layout here:
+------------+-------+
| Address | Value |
+------------+-------+
| 0x76543210 | 0x4A | <- firstName[0] - 'J'
| 0x76543211 | 0x6F | <- firstName[1] - 'o'
| 0x76543212 | 0x6E | <- firstName[2] - 'n'
| 0x76543213 | 0x00 | <- firstName[3] - '\0'
+------------+-------+
| 0x76543214 | 0x4D | <- lastName[0] - 'M'
| 0x76543215 | 0x65 | <- lastName[1] - 'e'
| 0x76543216 | 0x65 | <- lastName[2] - 'e'
| 0x76543217 | 0x00 | <- lastName[3] - '\0'
+------------+-------+
Given this memory layout if you were to do cout << firstName << ' ' << lastName you'd get:
0x76543210 0x76543214
These arrays are really just a pointer to their first element! This illustrates Array to Pointer Decay, which you can read more about here: http://en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay
Before we move on there's something important here to note, chars take up exactly 1-byte so the address of each subsequent char in the array will simply be the next address. That's leveraged by the Subscript Operator in this way: firstName[1] is equivalent to *(firstName + 1). This is true for chars but is also true for any other type which takes up more than 1-byte. Let's take for example: short siArray = { 1, 2, 3, 4 }, a possible memory layout of siArray would look like:
+------------+--------+
| Address | Value |
+------------+--------+
| 0x76543218 | 0x0001 | <- siArray[0] - 1
| 0x7654321A | 0x0002 | <- siArray[1] - 2
| 0x7654321C | 0x0003 | <- siArray[2] - 3
| 0x7654321E | 0x0004 | <- siArray[3] - 4
+------------+--------+
Even though cout << siArray << ' ' << &(siArray[1]) will output:
0x76543218 0x7654321A
*(siArray + 1) will still index the same element of siArray as siArray[1]. This is because when doing pointer arithmetic c++ considers the type of the address being operated on, thus incrementing a short* will actually increase the address by sizeof(short). You can read more about pointer arithmetic here: http://en.cppreference.com/w/cpp/language/operator_arithmetic
Lastly let's look at how c++ stores 2-dimensional arrays. Given: char name[2][4] = { { 'J', 'o', 'n', '\0' }, { 'M', 'e', 'e', '\0' } } a possible memory layout would be:
+------------+-------+
| Address | Value |
+------------+-------+
| 0x76543220 | 0x4A | <- name[0][0] - 'J'
| 0x76543221 | 0x6F | <- name[0][1] - 'o'
| 0x76543222 | 0x6E | <- name[0][2] - 'n'
| 0x76543223 | 0x00 | <- name[0][3] - '\0'
| 0x76543224 | 0x4D | <- name[1][0] - 'M'
| 0x76543225 | 0x65 | <- name[1][1] - 'e'
| 0x76543226 | 0x65 | <- name[1][2] - 'e'
| 0x76543227 | 0x00 | <- name[1][3] - '\0'
+------------+-------+
Since we know an 1-dimensional array value is really just a pointer, we can see from this memory layout that name[0] is not a pointer, it's just the first character of the first array. Thus name does not contain 2 1-dimensional array pointers, but contains the contents of the 2 arrays. (Incidentally on a 32-bit machine not storing the pointers saves 8-bytes of memory, which is pretty substantial for an 8-byte 2-dimensional array.) Thus trying to treat name as a char** would try to use the characters as a pointer.
Having understood this we really just need to avoid using c++'s pointer arithmetic to find dereference the value. To do that we'll need to work with a char* so that adding 1 is really just adding 1. So for example:
const short si2DArray[2][3] = { { 11, 12, 13 }, { 21, 22, 23 } };
const auto psi2DPointer = reinterpret_cast<const char*>(si2DArray);
for(auto i = 0U; i < size(si2DArray); ++i) {
for(auto j = 0U; j < size(*si2DArray); ++j) {
cout << *reinterpret_cast<const short*>(psi2DPointer + i * sizeof(*si2DArray) + j * sizeof(**si2DArray)) << '\t';
}
cout << endl;
}
Live Example
Note that in this example even though I reference si2DArray thought psi2DPointer I'm still using information from si2DArray to do the indexing, namely:
How many arrays are in the major dimension: size(si2DArray)
How many elements are in the minor dimension: size(*si2DArray)
What is the size in memory of the minor dimension: sizeof(*si2DArray)
What is the element type of the array: sizeof(**si2DArray)
You can thus see that the loss of information from converting from an array to a pointer is substantial. You may be tempted to preserve the element type, thereby also simplifying the pointer arithmetic. It's worthwhile to note that only a conversion to char* is considered defined behavior by reinterpret_cast: http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing
I want to convert 2D array of objects to pointer-to-pointer. How can I do this?
Why? Is it because an interface expects a pointer to pointers?
If so, you'll need to create a new array that contains those pointers.
Activity solution[a][b];
Activity* solutionPtrs[a];
for (int i = 0; i < a; ++i)
solutionPtrs[a] = solution[a];
Activity** mother = solutionPtrs;
Why can't you just cast a 2D array of T to T**? Well, because they have nothing to do with one another!
You can cast a T[a] to a T* because you get a pointer to the first element of the array.
You can do this with 2D arrays as well, but if you have a T[a][b] then it decays to a (T[b])* because a 2D array is not an array of pointers, it's an array of arrays.
Not sure if you were looking for something like this. You should provide more details about what you want to achieve. They are fundamentally different types. One solution is to below.
For the record, if someone finds it useful:
// define matrix
double A[3][3] = {
{ 1, 2, 3},
{ 4, 5, 6},
{ 7, 8, 9}
};
// allocate memory
double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
for (int i = 0; i < 3; i++)
A_ptr[i] = (double *) malloc(sizeof (double) * 3);
// copy matrix
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
A_ptr[i][j] = A[i][j];
printf(" %f ", A_ptr[i][j]);
}
}
You can't. They are fundamentally different types.