What does "int *[5]" indicate in c? [duplicate] - c

This question already has answers here:
What is the meaning of int (*pt)[5] in c [duplicate]
(3 answers)
Closed 7 years ago.
I was going through study materials from my previous year at University, and I saw a question like:
What is the difference between int *a and int a[5] and int *[5]. What does the last one indicate?

the int *a[5] declares an array of pointers to int.
the easiest was to determine the specifics of a variable declaration is read it from right to left.

In a nutshell:
int *a - creates a pointer to an int. This should contain the memory address of another int.
Example values of *a are 0x00001, 0x000057, etc.
int a[5] - creates an array that contains five int elements with each element containing an int values.
Here's a visualization of the possible values of each element in the array:
-------------------------
| Array element | Value |
-------------------------
| a[0] | 1 |
| a[1] | 2 |
| a[2] | 3 |
| a[3] | 4 |
| a[4] | 5 |
-------------------------
int *a[5] - creates an array that contains five pointer to an int elements which each element containing the memory address of another int.
Here's a visualization of the possible values of each element in the pointer array:
-------------------------
| Array element | Value |
-------------------------
| a[0] | 0x000 |
| a[1] | 0x001 |
| a[2] | 0x002 |
| a[3] | 0x003 |
| a[4] | 0x004 |
-------------------------

Related

Multi-dimensional Array Initialization in C

I'm piddling around with an Arduino and I have next to no programming in C.
In looking through some example code I came across this array variable declaration:
byte myArray[][6] = {"0"};
I get that this is declaring an array with unspecified rows and 6 columns.
What I don't understand is the {"0"}.
Upon the execution of this like of code, what will this variable contain?
Thanks!
The expression will initialize an array that looks like this:
myArray[0][0]
^
| +----> myArray[0][1]
| |
+---+----+---+---+---+---+
myArray[0] -----> |'0'|'\0'| | | | |
+---+----+---+---+---+---+
As you don't specify the first dimension and you only initialze 1 line it defaults to byte myArray[1][6].
If you were to initialize your array with, for instance:
byte myArray[][6] = {"0", "1"};
Then it would be:
myArray[0][0]
^
| +----> myArray[0][1]
| |
+---+----+---+---+---+---+
myArray[0] -----> |'0'|'\0'| | | | |
+---+----+---+---+---+---+
myArray[1] -----> |'1'|'\0'| | | | |
+---+----+---+---+---+---+
^ |
| |
myArray[1][0] |
+--->myArray[1][1]
In this case, because you initialize 2 lines, it defaults to byte myArray[2][6].
The string literal "0" is equivalent to the compound literal (char[]){ '0', '\0' }. So the declaration is equivalent to:
byte myArray[][6] = { { '0', '\0' } };
So the resulting array will be one row that contains an ASCII 0 (or a 0 appropriate to whatever the target character set is) followed by 5 \0 or NUL bytes.

struct padding extra byte after member [duplicate]

This question already has answers here:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?
(13 answers)
Closed 4 years ago.
#include <stdio.h>
#include <stdint.h>
typedef struct s{
uint8_t a[1];
uint16_t b;
uint8_t c[1];
}s_t;
int main()
{
printf("size = %d", sizeof(s_t));
return 0;
}
I am not sure why the output of this program is 6 bytes and not 5. Why does the compiler pad an extra byte after the last member ? It also seems like, if you make the last member array length 3, the padding makes the size 8. I am unable to explain this since this is not the case for 2 arrays only.
Here is an illustration of the alignment that the compiler generates:
Bytes:
+-----+---------------+
| 0 | a[1] |
+-----+---------------+
| 1 | N/A (padding) |
+-----+---------------+
| 2 | b |
+-----+---------------+
| 3 | b |
+-----+---------------+
| 4 | c |
+-----+---------------+
As 16-bit quantities:
+---+------+----+
| 0 | a[i] | |
+---+------+----+
| 2 | b |
+---+------+----+
| 4 | c | |
+---+------+----+
Processors like to fetch 16-bit quantities from even addresses.
When they are on odd addresses, the computer may have to make 2 16-bit fetches, and extract the unaligned data out of them.
The easy method to eliminate this extra fetch is to add padding bytes so that 16-bit quantities align to even addresses.
A rule of thumb is to place the larger items first, then the smaller.
Applying this rule:
+---+------+
| 0 | b |
+---+------+
| 2 | a[1] |
+---+------+
| 3 | c |
+---+------+
The rule eliminates the need for an extra padding byte.

About using pointers for 2D array definition in C

When we're defining a 2D array as in:
int *a[5];
Which dimension does the "5" define? The first or the second?
It's not a "2D" array. It's a 1-dimensional array of pointers to int. As such the array size designates that it has space for 5 pointers. Each individual pointer can point to the first element of a buffer with different size.
A "true 2D array" is the colloquial "array of arrays" int a[M][N]. Here the expression a[i] evaluates to the array of N integers, at position i.
Each a[i] points to a single int, which may be the first element in a sequence of int objects, like so:
a[0] a[1] a[2] a[3] a[4]
+----+----+----+----+----+
| | | | | |
+----+----+----+----+----+
| | | | |
| | | ... ...
| | +-------------------------------+
| +-------------------+ |
+-------+ | |
| | |
v v v
+---+ +---+ +---+
a[0][0] | | a[1][0] | | a[2][0] | |
+---+ +---+ +---+
a[0][1] | | a[1][1] | | a[2][1] | |
+---+ +---+ +---+
... ... ...
Thus, each a[i] can represent a "row" in your structure. You can dynamically allocate each "row" as
a[i] = malloc( sizeof *a[i] * row_length_for_i );
or you can set it to point to an existing array:
int foo[] = { 1, 2, 3 };
int bar[] = { 5, 6, 7, 8, 9 };
...
a[0] = foo;
a[1] = bar;
As shown in the example above, each "row" may have a different length.
I keep putting scare quotes around "row" because what you have is not a true 2D array - it's not a contiguous sequence of elements. The object immediately following a[0][N-1] will most likely not be a[1][0]. What you have is a sequence of pointers, each of which may point to the first element of a sequence of int, or to a single int, or to nothing at all.

How memory is allocated when we use malloc to create 2-dimensional array?

I want to create an integer array[5][10] using malloc(). The difference between memory address of array[0] and array[1] is showing 8. Why?
#include <stdio.h>
#include <stdlib.h>
int main() {
int *b[5];
for (int loop = 0; loop < 5; loop++)
b[loop] = (int*)malloc(10 * sizeof(int));
printf("b=%u \n", b);
printf("(b+1)=%u \n", (b + 1));
printf("(b+2)=%u \n", (b + 2));
}
The output is:
b=2151122304
(b+1)=2151122312
(b+2)=2151122320
The difference between memory address of array[0] and array[1] is showing 8. Why?
That's because sizeof of a pointer on your platform is 8.
BTW, use of %u to print a pointer leads to undefined behavior. Use %p instead.
printf("(b+1)=%p \n",(b+1));
printf("(b+2)=%p \n",(b+2));
Difference between array of pointers and a 2D array
When you use:
int *b[5];
The memory used for b is:
&b[0] &b[1] &b[2]
| | |
v v v
+--------+--------+--------+
| b[0] | b[1] | b[2] |
+--------+--------+--------+
(b+1) is the same as &b[1]
(b+2) is the same as &b[2]
Hence, the difference between (b+2) and (b+1) is the size of a pointer.
When you use:
int b[5][10];
The memory used for b is:
&b[0][0] &b[1][0] &b[2][0]
| | |
v v v
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ ...
| | | | | | | | | | | | | | | | | | | | | ...
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ ...
(b+1) is the same as &b[1], The value of that pointer is the same as the value of &b[1][0] even though they are pointers to different types.
(b+2) is the same as &b[2], The value of that pointer is the same as the value of &b[2][0]
Hence, the difference between (b+2) and (b+1) is the size of 10 ints.
First, with int *b[5] you are not creating a two dimensional array, but an array of pointers.
The elements of the array b are pointers. Each occupies the size of a pointer, which depends on your architecture. In a 64-bits architecture it will probably occupy 64 bits (8 bytes). You can check that by printing sizeof(int*) or sizeof(b[0])
Memory allocation will look like
b
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[0]+--------------> | | | | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[1]+--------------> | | |....... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[2]+--------------> | | | ...... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[3]+--------------> | | | ...... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
| | +------+------+-----------+-----+-----+-----+-----+
| b[4]+--------------> | | | ...... | | | | |
| | +------+------+-----------+-----+-----+-----+-----+
+-----+
b will point to b[0], after decay, and b + 1 will give the address of b[1]. Size of pointer on your machine is 8 bytes, therefore you are getting a difference of 8 in the address.
Beside of this
Do not cast return value of malloc
b[loop]=malloc(10*sizeof(int));
and use %p for pointer data type
printf("b=%p \n",(void *)b);
printf("(b+1)=%p \n",(void *)(b+1));
printf("(b+2)=%p \n",(void *)(b+2));
What you've declared is not technically a two dimensional array but an array of pointers to int, each of which points to an array of int. The reason array[0] and array[1] are 8 bytes apart is because you have an array of pointers, and pointers on your system are 8 bytes.
When you allocate each individual 1 dimensional array, they don't necessarily exist next to each other in memory. If on the other hand you declared int b[5][10], you would have 10 * 5 = 50 contiguous integers arranged in 5 rows of 10.

I am stuck with an output in C ( Multi-dimensional array operations) [duplicate]

This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 8 years ago.
#include <stdio.h>
void main()
{
int arr[3][2]={2,3,4,5,6,7};
printf("%d\n",arr);
printf("%d\n",arr[1]);
printf("%d",arr[1][2]);
}
The above code when compiled in Borland Turbo C++ gives the output
8682
8686
6
I don't understand how this program works. I understand that while printing arr it returns the base address as 8682 and arr[1] returns next address location 8686 (integer is 4 bytes) but why is arr[1][2] not flashing an error as arr[1][2] is out of bounds?
Strictly speaking, it's undefined behavior. However, if you look at how array indices are treated, you will see why it's working.
arr
|
v
+-----+-----+-----+-----+-----+-----+
| 2 | 3 | 4 | 5 | 6 | 7 |
+-----+-----+-----+-----+-----+-----+
arr[0]
|
v
+-----+-----+-----+-----+-----+-----+
| 2 | 3 | 4 | 5 | 6 | 7 |
+-----+-----+-----+-----+-----+-----+
arr[1]
|
v
+-----+-----+-----+-----+-----+-----+
| 2 | 3 | 4 | 5 | 6 | 7 |
+-----+-----+-----+-----+-----+-----+
arr[1][0]
|
v
+-----+-----+-----+-----+-----+-----+
| 2 | 3 | 4 | 5 | 6 | 7 |
+-----+-----+-----+-----+-----+-----+
arr[1][2]
|
v
+-----+-----+-----+-----+-----+-----+
| 2 | 3 | 4 | 5 | 6 | 7 |
+-----+-----+-----+-----+-----+-----+
why arr[1][2] is not flashing an error as arr[1][2] is out of bound
if my memory serves me right, C wont complain about array out of bounds errors. It will instead simply allow you to go out of bounds.
In C, errors are not thrown for out of bounds array accesses - in fact it doesn't even make any check! Instead the system will just access whatever happens to be at that spot in memory (one of the major dangers of C programs).
Here's an explanation of what is happening here. Take this code here:
arr[1][2]
What happens internally actually looks like this:
*(arr + 1 * 2 + 2) // the 2 comes from the second dimension size of the array
The 2D array internally is stored as a one-dimensional array with each row coming after the previous row:
arr[3][2] = {2, 3, 4, 5, 6, 7};
// is the same as
arr[6] = {2, 3, 4, 5, 6, 7};
The math from arr[1][2] works out to accessing arr[5], which is why you get 6 as the value.

Resources