So, I am learning C right now, and wanted some clarification on some things.
I've learned that if we wanted to create a dynamic arrays we could use the following line of code:
int *arr = malloc(10 * sizeof(int));
I understand that, in this case, arr is a pointer being allocated the equivalent of an array of 10 ints in terms of bytes. I also understand that you can treat arr as an array (from arr[0] to arr[9].
Does that mean all pointers that are allocated memory can be treated as an array?
Like could this be treated as an array?
int *single = malloc(sizeof(int));
Or could this be treated as an array?
int *half = malloc(sizeof(int) * 1.5)
Ignoring the array size, yes all pointers can be used arrays (meaning you can index them).
The number of elements should be an integer, with truncation for valid access (i.e., 1.5 means 1 item).
You request number of bytes from malloc, it makes sense that this is a multiple of the item size.
You should read about pointer arithmetic.
Array names can also be used as pointers (e.g., *array) but you can't assign to them or modify them (e.g., ++array).
Like could this be treated as an array?
int *single = malloc(sizeof(int));
Sure, it can be treated as an array int single[1]
Or could this be treated as an array?
int *half = malloc(sizeof(int) * 1.5)
Yes, but it will have the same effect as previous snippet but you will just waste 2 additional bytes. If you try to write in half[2], you can corrupt some memory.
Related
I'm very new to C and I have trouble understanding array pointers. I'm trying to make a array bigger,I copy all of its element to new bigger array but I can't make original variable to point the new array. I'm use to C# where you can do
double[] array1 = new double[5];
double[] array2 = new double[10];
array1 = array2;
I did something similar using int array
int array1 [5];
int array2 [10];
*array1 = &array2;
and it compile but crash the program. Same lines but double or char[] (I was told to use char[] instead of sting in C) do not even compile
[Error] incompatible types when assigning to type 'double' from type 'double (*)[(sizetype)(newsize)]'
The results I found on the topic told me to use double* array1 for variable type but this change the interactions with that variable.
If someone can explain the concept to me or at least tell me what to search for that will be huge help.
I do know the basics of pointers!
There are a few things you need to know about arrays (and pointers):
The first is that arrays and pointers are two different things;
The second is that an array can decay to a pointer to its first element. So if you use array1 (from your example) when a pointer is expected, that's the same as doing &array1[0]. The type of such a pointer is a pointer to a single element type (so for array1 the type will be int *);
The third thing is that for any array of pointer a and index i, the expression a[i] is exactly equal to *(a + i). That means *array1 (again from your example) is the same as array1[0] (*array1 is equal to *(array1 + 0) which is equal to array1[0]);
An array will have a fixed size. Once defined the size of an array can't change;
Lastly when you get a pointer to an array (as in &array2) then you get a pointer to the actual array, not to one of its elements. The type of e.g. &array2 is int (*)[10].
Now we can puzzle together the statement
*array1 = &array2;
If we do the array-indexing replacement for *array1 then we get
array[0] = &array2;
And here we can see a big problem: The type of a single element of array1 is a plain int. So what the assignment is trying to do is to assign a pointer to an array (of type int (*)[10]) to a single int.
If you want to copy all the elements from one array to another, then use the memcpy function. You're not allowed to assign between arrays.
But beware of the different sizes for array1 and array2. If you go out of bounds of an array (or other allocated memory) you will have undefined behavior.
In C there is no way to make an array variable "reference" a different variable. If you need to use "references" they can be emulated using pointers:
int *pointer1 = array1; // array1 here will decay to &array[0]
int *pointer2 = array2; // Same here for array2
With the above definition pointer1 is (in a way) "referencing" array1. You can now use pointer1 and array1 almost interchangeably.
One major difference between using pointers and arrays is how their sizes are calculated: When you do sizeof on an array you get the size (in bytes) of the whole array. Assuming 32-bit int (the most common) then sizeof array1 will return 5 * 4 (or 20) as the size. If you get the size of a pointer, you get the size of the pointer itself, not what it might point to. So sizeof pointer1 will return either 4 or 8 (depending on if you're in a 32-bit or 64-bit system).
Going back to references, we can now change where pointer1 is pointing:
pointer1 = pointer2; // Assuming pointer2 is unchanged, equivalent to pointer1 = array2
Now pointer1 and pointer2 are pointing to the same array, array2.
In C# you can overload the = to copy the arrays. In C it is just simple assignment.
In C arrays decays to pointers for the sake of simplicity. In C *(array + N) == array[N] and *array == array[0]
int array1 [5]; it is not the array of pointers only integers so *array1 = &array2; assigns array[0] with address of the first element of the the array2 converted to signed integer which generally doesn't make too much sense and it does not copy array2 to array
To copy array you need to use memcpy or the loop to copy the element. You need to make sure that the destination array is large enough to accommodate the second array. C will not change the destination array size.
The assignments that your are doing is wrong. Basically a pointer points to a block of memory. from your code I can understand that array1 = array2; and *array1 = &array2; is wrong.
Syntax in C is something like this data-type* pointer-variable = (data-type*)malloc(no. of bytes you want);
See consider you want 10 block of memory of type int
int *p = (int *)malloc(10 * sizeof(int))
sizeof(int) return 4 bytes.
Now p points to 10 * 4 = 40 bytes of memory, I multiplied by 4 because int is usually of 4 bytes and double is of 8 bytes and so on.
Follow this link to understand C - Data Types
Now regarding changing pointers refer below example and read the comments
int *q = NULL // declare a pointer of same type as the block of memory it is going to point
q = p; //now q and p point same memory of 40 bytes, means value at q[0] is equal to p[0]
When you have an integer pointer and you increment it by p++ it will point to next memory location p[1], pointer will be exactly incremented by 4 bytes as int size is 4 bytes and for double it will be 8 bytes, for char it will be 1 byte and so on.
Now if you want to increase the size of dynamically allocated memory you can use realloc please follow this link to understand more.
Dynamic Memory Allocation in C
int *p = NULL;
// Dynamically allocate memory using malloc()
p = (int*)malloc(no. of bytes, sizeof(int));
// Dynamically re-allocate memory using realloc()
p = realloc(p, (no. of bytes) * sizeof(int));
// Avoid memory leaks
free(p);
Syntax in C++ is something like this data-type* pointer-variable = new data-type[size];
See consider you want 10 block of memory of type int
int *p = new int[10]
Just use new operator to allocate block of memory and use delete to free allocated memory to avoid memory leaks.follow this link
new and delete operators in C++ for dynamic memory
Or If you are looking for containers where you don't know how much memory should be allocated the use standard template library vector, it helps creating dynamic arrays.follow this link
Vector in C++ STL
Three questions in 1.
If I have a 2-D array -
int array_name[num_rows][num_columns]
So it consists of num_rows arrays -each of which is an array of size = num_columns. Its equivalent representation using an array of pointers is-
int* array_name[num_rows]
-so the index given by [num_rows] still shows the number of 1-D arrays - somewhere using malloc we can then specify the size of each of the 1-D arrays as num_columns. Is that right? I saw some texts telling
int* array_name[num_columns]
will the indices not get switched in this case ?
For a ID array I specify size dynamically as-
int *p;
p = (int*) malloc (size * sizeof(int))
For 2 D arrays do I specify the size of entire 2-D array or of one 1-D array in malloc -
int*p [row_count];
p = (int*) malloc (row_count * column_count * sizeof(int))
or
p = (int*) malloc (column_count * sizeof(int))
I think it should be the second since p is a pointer to a 1-D array and p+1 is a pointer to a 1-D array etc. Please clarify.
For ques 2 - what if p was defined as -
int **p; rather than
int * p[row_count]
How will the malloc be used then? I think it should be -
p = (int*) malloc (row_count * column_count * sizeof(int))
Please correct, confirm, improve.
Declaring :
int *array_name[num_rows];
or :
int *array_name[num_columns];
is the same thing. Only the name changes, but your variable is still referring to rows because C is a row major so you should name it row.
Here is how to allocate a 2D array :
int (*p)[column] = malloc (sizeof(int[row][column]);
An int ** can be allocated whereas int [][] is a temporary array defined only in the scope of your function.
Don't forget that a semicolon is needed at the end of nearly every line.
You should read this page for a more complete explanation of the subject
(and 2.)
If I have a 2-D array
int array_name[num_rows][num_columns];
So it consists of num_rows arrays -each of which is an array of size = num_columns.
If both num_rows and num_columns are known at compile time, that line declares an array of num_rows arrays of num_columns ints, which, yes, is commonly referred as a 2D array of int.
Since C99 (and optionally in C11) you can use two variables unknown at compile time and end up declaring a Variable-Length Array, instead.
Its equivalent representation using an array of pointers is
int* array_name[num_rows];
So the index given by [num_rows] still shows the number of 1-D arrays - somewhere using malloc we can then specify the size of each of the 1-D arrays as num_columns. Is that right?
Technically, now array_name is declared as an array of num_rows pointers to int, not arrays. To "complete" the "2D array", one should traverse the array and allocate memory for each row. Note that the rows could have different sizes.
Using this form:
int (*array_name)[num_columns];
// ^ ^ note the parenthesis
array_name = malloc(num_rows * sizeof *array_name);
Here, array_name is declared as a pointer to an array of num_columns ints and then the desired number of rows is allocated.
3.
what if p was defined as int **p;
The other answers show how to allocate memory in this case, but while it is widely used, it isn't always the best solution. See e.g.:
Correctly allocating multi-dimensional arrays
I have a variable N. I need a 6xNxN array.
Something like this:
int arr[6][N][N];
But, obviously, that doesn't work.
I'm not sure how I'd go about allocating this so that I can access, e.g. arr[5][4][4] if N is 5, and arr[5][23][23] if N is 24.
Note that N will never change, so I'll never have to reallocate arr.
What should I do? Will int ***arr = malloc(6 * N * N * sizeof(int)); work?
You can allocate your 3-dimensional array on the heap as
int (*arr)[N][N] = malloc(sizeof(int[6][N][N]));
After use, you can free as
free(arr);
Another way of writing the same as suggested by #StoryTeller is -
int (*arr)[N][N] = malloc(6u * sizeof(*arr));
But here you need to be careful about the u after 6 to prevent signed arithmetic overflow.
Also, there can still be issues on platforms where size_t is smaller in width that int as suggested by #chqrlie, but that won't be the case on "most" commonly used platforms and hence you are fine using it.
int arr[6][N][N]; will work just fine. You merely need to update your compiler and C knowledge to the year 1999 or later, when variable-length arrays (VLA) were introduced to the language.
(If you have an older version of GCC than 5.0, you must explicitly tell it to not use an ancient version of the C standard, by passing -std=c99 or -std=c11.)
Alternatively if you need heap allocation, you can do:
int (*arrptr)[Y][Z] = malloc( sizeof(int[X][Y][Z]) );
You cannot do int ***arr = malloc(6 * N * N * sizeof(int)); since a int*** cannot point at a 3D array. In general, more than two levels of indirection is a certain sign that your program design is completely flawed.
Detailed info here: Correctly allocating multi-dimensional arrays.
What you want can't work directly. For indexing a multi-dimensional array, all but the very first dimension need to be part of the type and here's why:
The indexing operator operates on pointers by first adding an index to the pointer and then dereferencing it. The identifier of an array evaluates to a pointer to its first element (except when e.g. used with sizeof, _Alignof and &), so indexing on arrays works as you would expect.
It's very simple in the case of a single-dimension array. With
int a[42];
a evaluates to a pointer of type int * and indexing works the following way: a[18] => *(a + 18).
Now in a 2-dimensional array, all the elements are stored contiguously ("row" after "row" if you want to understand it as a matrix), and what's making the indexing "magic" work is the types involved. Take for example:
int a[16][42];
Here, the elements of a have the type int ()[42] (42-element array of int). According to the rules above, evaluating an expression of this type in most contexts again yields an int * pointer. But what about a itself? Well, it's an array of int ()[42] so a will evaluate to a pointer to 42-element array of int: int (*)[42]. Then let's have a look at what the indexing operator does:
a[3][18] => *(*(a + 3) + 18)
With a evaluating to the address of a with type int (*)[42], this inner addition of 3 can properly add 42 * sizeof(int). This would be impossible if the second dimension wasn't known in the type.
I guess it's simple to deduce the example for the n-dimensional case.
In your case, you have two possibilities to achieve something similar to what you want.
Use a dynamically allocated flat array with size 6*N*N. You can calculate the indices yourself if you save N somewhere.
Somewhat less efficient, but yielding better readable code, you could use an array of pointers to arrays of pointers to int (multiple indirection). You could e.g. do
int ***a = malloc(6 * sizeof *int);
for (size_t i = 0; i < 6; ++i)
{
a[i] = malloc(N * sizeof *(a[i]));
for (size_t j = 0; j < N ++j)
{
a[i][j] = malloc(N* sizeof *(a[i][j]));
}
}
// add error checking to malloc calls!
Then your accesses will look just like those to a normal 3d array, but it's stored internally as many arrays with pointers to the other arrays instead of in a big contiguous block.
I don't think it's worth using this many indirections, just to avoid writing e.g. a[2*N*N+5*N+4] to access the element at 2,5,4, so my recommendation would be the first method.
Making a simple change to the declaration on this line and keeping the malloc can easily solve your problem.
int ***arr = malloc(6 * N * N * sizeof(int));
However, int *** is unnecessary (and wrong). Use a flat array, which is easy to allocate:
int *flatarr = malloc(6 * N * N * sizeof(int));
This works for three dimensions, and instead of accessing arr[X][Y][Z] as in the question, you access flatarr[(X*N*N) + (Y*N) + Z]. In fact, you could even write a handy macro:
#define arr(X,Y,Z) flatarr[((X)*N*N) + ((Y)*N) + (Z)]
This is basically what I've done in my language Cubically to allow for multiple-size cubes. Thanks to Programming Puzzles & Code Golf user Dennis for giving me this idea.
Here consider the following sample of code:
int *a = malloc(sizeof(int) * n);
Can this code be used to define an array a containing n integers?
int *a = malloc(sizeof(int) * n);
Can this code be used to define an array a containing n integers?
That depends on what you mean by "define an array".
A declaration like:
int arr[10];
defines a named array object. Your pointer declaration and initialization does not.
However, the malloc call (if it succeeds and returns a non-NULL result, and if n > 0) will create an anonymous array object at run time.
But it does not "define an array a". a is the name of a pointer object. Given that the malloc call succeeds, a will point to the initial element of an array object, but it is not itself an array.
Note that, since the array object is anonymous, there's nothing to which you can apply sizeof, and no way to retrieve the size of the array object from the pointer. If you need to know how big the array is, you'll need to keep track of it yourself.
(Some of the comments suggest that the malloc call allocates memory that can hold n integer objects, but not an array. If that were the case, then you wouldn't be able to access the elements of the created array object. See N1570 6.5.6p8 for the definition of pointer addition, and 7.22.3p1 for the description of how a malloc call can create an accessible array.)
int *a = malloc(sizeof(int) * n);
Assuming malloc() call succeeds, you can use the pointer a like an array using the array notation (e.g. a[0] = 5;). But a is not an array itself; it's just a pointer to an int (and it may be a block of memory which can store multiple ints).
Your comment
But I can use an array a in my program with no declaration otherwise
suggests this is what you are mainly asking about.
In C language,
p[i] == *(p + i) == *(i + p) == i[p]
as long as one of i or p is of pointer type (p can an array as well -- as it'd be converted into a pointer in any expression). Hence, you'd able to index a like you'd access an array. But a is actually a pointer.
Yes. That is exactly what malloc() does.
The important distinction is that
int array[10];
declares array as an array object with enough room for 10 integers. In contrast, the following:
int *pointer;
declares pointer as a single pointer object.
It is important to distiguinsh that one of them is a pointer and that the other as an actual array, and that arrays and pointers are closely related but are different things. However, saying that there is no array in the following is also incorrect:
pointer = malloc(sizeof (int) * 10);
Because what this piece of code does is precisely to allocate an array object with room for 10 integers. The pointer pointer contains the address of the first element of that array.(C99 draft, section 7.20.3 "Memory management functions")
Interpreting your question very literally, the answer is No: To "define an array" means something quite specific; an array definition looks something like:
int a[10];
Whereas what you have posted is a memory allocation. It allocates a space suitable for holding an array of 10 int values, and stores a pointer to the first element within this space - but it doesn't define an array; it allocates one.
With that said, you can use the array element access operator, [], in either case. For instance the following code snippets are legal:
int a[10];
for (int i = 0; i < 10; i++) a[i] = 0;
and
int *a = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) a[i] = 0;
There is a subtle difference between what they do however. The first defines an array, and sets all its elements to 0. The second allocates storage which can hold an equivalently-typed array value, and uses it for this purpose by initialising each element to 0.
It is worth pointing out that the second example does not check for an allocation error, which is generally considered bad practice. Also, it constitutes a potential memory leak if the allocated storage is not later freed.
In the language the Standard was written to describe (as distinct from the language that would be described by a pedantic literal reading of it), the intention was that malloc(n) would return a pointer that would, if cast to a T*, could be treated as a pointer to the first element of a T[n/sizeof T*]. Per N1570 7.22.3:
The
pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to
a pointer to any type of object with a fundamental alignment requirement and then used
to access such an object or an array of such objects in the space allocated (until the space
is explicitly deallocated).
The definition of pointer addition and subtraction, however, do not speak of acting upon pointers that are "suitably aligned" to allow access to arrays of objects, but rather speak of pointers to elements of actual array objects. If a program accesses space for 20 int objects, I don't think the Standard does actually says that the resulting pointer would behave in all respects as though it were a pointer to element [0] of an int[20], as distinct from e.g. a pointer to element [0][0] of an int[4][5]. An implementation would have to be really obtuse not to allow it to be used as either, of course, but I don't think the Standard actually requires such treatment.
This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 6 years ago.
int main()
{
matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
int **ptr = (int**)matrix;
printf("%d%d",**matrix,*ptr);
}
But when a 2-d array is passed as a parameter it is typecasted into (*matrix)[2] ..
what type does the compiler store this array as... is it storing as a 2-d array or a double pointer or an pointer to an array .. If it is storing as an array how does it interprets differently at different situations like above. Please help me understand.
Is 2d array a double pointer?
No. This line of your program is incorrect:
int **ptr = (int**)matrix;
This answer deals with the same topic
If you want concrete image how multidimensional arrays are implemented:
The rules for multidimensional arrays are not different from those for ordinary arrays, just substitute the "inner" array type as element type. The array items are stored in memory directly after each other:
matrix: 11 22 33 99 44 55 66 110
----------- the first element of matrix
------------ the second element of matrix
Therefore, to address element matrix[x][y], you take the base address of matrix + x*4 + y (4 is the inner array size).
When arrays are passed to functions, they decay to pointers to their first element. As you noticed, this would be int (*)[4]. The 4 in the type would then tell the compiler the size of the inner type, which is why it works. When doing pointer arithmetic on a similar pointer, the compiler adds multiples of the element size, so for matrix_ptr[x][y], you get matrix_ptr + x*4 + y, which is exactly the same as above.
The cast ptr=(int**)matrix is therefore incorrect. For once, *ptr would mean a pointer value stored at address of matrix, but there isn't any. Secondly, There isn't a pointer to matrix[1] anywhere in the memory of the program.
Note: the calculations in this post assume sizeof(int)==1, to avoid unnecessary complexity.
No. A multidimensional array is a single block of memory. The size of the block is the product of the dimensions multiplied by the size of the type of the elements, and indexing in each pair of brackets offsets into the array by the product of the dimensions for the remaining dimensions. So..
int arr[5][3][2];
is an array that holds 30 ints. arr[0][0][0] gives the first, arr[1][0][0] gives the seventh (offsets by 3 * 2). arr[0][1][0] gives the third (offsets by 2).
The pointers the array decays to will depend on the level; arr decays to a pointer to a 3x2 int array, arr[0] decays to a pointer to a 2 element int array, and arr[0][0] decays to a pointer to int.
However, you can also have an array of pointers, and treat it as a multidimensional array -- but it requires some extra setup, because you have to set each pointer to its array. Additionally, you lose the information about the sizes of the arrays within the array (sizeof would give the size of the pointer). On the other hand, you gain the ability to have differently sized sub-arrays and to change where the pointers point, which is useful if they need to be resized or rearranged. An array of pointers like this can be indexed like a multidimensional array, even though it's allocated and arranged differently and sizeof won't always behave the same way with it. A statically allocated example of this setup would be:
int *arr[3];
int aa[2] = { 10, 11 },
ab[2] = { 12, 13 },
ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;
After the above, arr[1][0] is 12. But instead of giving the int found at 1 * 2 * sizeof(int) bytes past the start address of the array arr, it gives the int found at 0 * sizeof(int) bytes past the address pointed to by arr[1]. Also, sizeof(arr[0]) is equivalent to sizeof(int *) instead of sizeof(int) * 2.
In C, there's nothing special you need to know to understand multi-dimensional arrays. They work exactly the same way as if they were never specifically mentioned. All you need to know is that you can create an array of any type, including an array.
So when you see:
int matrix[2][4];
Just think, "matrix is an array of 2 things -- those things are arrays of 4 integers". All the normal rules for arrays apply. For example, matrix can easily decay into a pointer to its first member, just like any other array, which in this case is an array of four integers. (Which can, of course, itself decay.)
If you can use the stack for that data (small volume) then you usually define the matrix:
int matrix[X][Y]
When you want to allocate it in the heap (large volume), the you usually define a:
int** matrix = NULL;
and then allocate the two dimensions with malloc/calloc.
You can treat the 2d array as int** but that is not a good practice since it makes the code less readable. Other then that
**matrix == matrix[0][0] is true