When an array is passed as an argument , the compiler generates a pointer to the array's first element and that pointer is passed to the function rather than the full array, so my question is why we can print the values of the array when we print array[i]?
void FunctionApi(int array[])
{
int i;
for(i=0;i<8;i++)
{
printf("Value =%d\n",array[i]);
//I understand the reason behind the following two lines but not the above line.
//printf("noOfElementsInArray=%d\n",*array);
//*array++;
}
}
int main()
{
int array[8]={2,8,10,1,0,1,5,3};
int noOfElementsInArray;
noOfElementsInArray=sizeof(array)/sizeof(int);
printf("noOfElementsInArray=%d\n",noOfElementsInArray);
FunctionApi(array);
return 0;
}
Array's elements are stored together in consecutive locations. That is why knowing the address of the initial element is sufficient to know where the rest of the elements are.
The only trick is knowing how many elements the array has. This is not passed along with the array, so you need to pass it separately. It is not a concern for your program because you hard-coded it to eight, but in general if you pass an array as an argument, you also need to pass its size as a separate parameter:
void FunctionApi(int array[], size_t count) {
int i;
for(i=0;i<count;i++) {
printf("Value =%d\n",array[i]);
}
}
As far as the noOfElementsInArray=sizeof(array)/sizeof(int); calculation goes, this trick works only in the caller, where array is an array, not a pointer to the initial element of the array. At this location the compiler knows that the size of the array is eight times the size of an int, so dividing out the sizeof(int) gives you the number of elements in the array.
Because array[i] is syntactically equivalent to *(array + i)
When you pass the name of an array, this is pointer to the first element as well as the entire array. Hence, when you access different elements as array[i] you are accessing successive data equivalent to *(array + i).
Related
I try to create an array of int in C, and then, use it in a custom function :
int a[] = {1,3,5,7,9};
int* new_a = extract(a, 2, 4);
// ...
int *extract(int* T, int a, int b){
int lenght_T = getLenghtOfSimpleArray(T);
...
}
I use the IDE visual code, when I inspect the code through the degugger, I get :
I don't understand why, in the debugger, the value of T is not {1,3,5,7,9}...
Where is my mystake ?
When you pass an array to a function it gets degraded to a pointer that points to the first element of the array. That means, T is an address in memory, so the big hex value shown in the debugger looks normal.
The debugger also shows *T, which is the value where the pointer points to, i.e. the first element of the array. The value is 1 as expected.
There is no way to find out the size/length of an array passed to a function this way, so it is not possible to make a working function getLenghtOfSimpleArray, except if you define an "invalid" value (sentinel value) which must be put to the last element of the array. In the general case, the caller must pass the size of the array to the function in addition to the array name = pointer to the first element.
example code with passing the array length
int a[] = {1,3,5,7,9};
int* new_a = extract(a, sizeof(a) / sizeof(a[0]), 2, 4);
int *extract(int* T, size_t length, int a, int b){
int lenght_T = getLenghtOfSimpleArray(T);
...
}
Arrays are not pointers. Pointers are not arrays.
T is not an array, it's a pointer to the first element. As you can see from your debugger, *T is 1, which is that first element.
Most debuggers support watches such as T[1] etc if you wish to inspect individual items beyond the first. Or they have a "range" feature that allows you to view a number of items.
In C, arrays are just values in the memory right next to each other, and the pointer only points to the first entry.
So in your case if you want to access the other values you have to access them with T[index]
The debugger only shows the first value of the array in this case.
I am trying to de-reference the 2D array inside the function islandPerimeter.
But I cannot understand why I am getting segfault for this.
Can someone point out what exactly I am doing wrong?
update:
So this was a part of a problem from leetcode I was trying to solve.I now understand it is not 2D array but a pointer. I am still confused over the int**. can someone explain it?
#include <stdio.h>
int islandPerimeter(int** grid, int gridSize, int gridColSize)
{
int perimeter=0,points=4,i=0;
for(int row=0;row<gridSize;++row)
{
for(int col=0;col<gridColSize;++col)
{
printf("%d ",grid[row][col]);
}
}
return perimeter;
}
int main()
{
int arr[4][5] = {{8,1,0,0,0},
{1,1,1,0,0},
{0,1,0,0,0},
{1,1,0,0,0}};
islandPerimeter(arr,4,5);
return 0;
}
A Pointer to Array
An array is a distinct type in C. It is a sequential collections of elements of a given type. In C a 2D array is actually an array of 1D arrays. In your case, you have an array [4] of int [5] (e.g. 4 - 5-elements arrays of int commonly called a 2D array of int)
Where new programmers normally get confused is how an array is treated on access. When an array is accessed, it is converted to a pointer to the first element. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) (pay attention to the 4 exceptions)
In the case of a 1D array, that is simple, the array is converted to a pointer to the first element of the array (the pointer is simply int*). In the case of a 2D array, the same holds true, the array is converted to a pointer to the first element -- but that first element is a 1D array of 5-int. (the pointer is a pointer-to-array of int [5], formally int (*)[5])
You can pass the 2D array (in your case) as a parameter of either int grid[4][5], int grid[][5], or to reflect that the array is converted to a pointer to the first element, int (*grid)[5]. The key is you must always provide the number of elements in the final dimension for your array (with additional '*' allowed for circumstances not relevant here) The 5 (or number of elements) must be an integer constant which is known at compile-time unless using a Variable Length Array (VLA), which are the topic for a separate discussion.
The same rule that on access an array is converted to a pointer to its first element applies to each dimension in your array, be it a 2D array or a 6D array. C11 Standard - 6.5.2.1 Array subscripting(p3)
Additionally, know the difference between a pointer-to-array (e.g. int (*grid)[5]) and an array-of-pointers (e.g. int *grid[5]). The parenthesis are required due to C Operator Precedence, the [..] has higher precedence than '*' in this case, so to require that *grid (in int *grid[5]) be evaluated as a pointer (instead of as an array grid[5]) you enclose it is parenthesis (*grid).
Thus resulting in a pointer-to-array of int [5], (int (*grid)[5]) instead of an array-of-pointers to int (5 of them) with int *grid[5].
A Pointer to Pointer
Contrast that with a pointer-to-pointer (e.g. int **, commonly called a double-pointer). You have two-levels of indirection represented by the two **. The pointer itself is a single-pointer -- to what? (another pointer, not to an array). You will generally use a double-pointer by first allocating a block of memory to hold some number of pointers, such as when you are dynamically allocating for an unknown number of allocated objects. This can be an unknown number of rows of an unknown number of columns of int or it can be an unknown number of strings, or a unknown number of structs, etc.. The key is your first level of indirection points to memory containing pointers.
Then for each of the available pointers you can allocate a block (e.g. in your case to hold 5 int and then assign the starting address for that block of memory to your first available pointer). You continue allocating for your columns (or strings or structs) and assigning the beginning address to each of your available pointers in sequence. When done, you can access the individual elements in your allocated collection using the same indexing you would for a 2D array. The difference between such a collection and a 2D array of arrays -- is the memory pointed to by each pointer need not be sequential in memory.
Telling Them Apart
The key to knowing which to use is to ask "What does my pointer point to?" Does it point to a pointer? Or, does it point to an array? If it points to another pointer, then you have a pointer-to-pointer. If the thing pointed to is an array, then you have a pointer-to-array. With that, you know what you need as a parameter.
Why the SegFault with int**
Type controls pointer arithmetic. Recall above, int** is a pointer-to-pointer, so how big is a pointer? (sizeof (a_pointer) - usually 8-bytes on x86_64, or 4-bytes on x86). So grid[1][0] is only one-pointer (8-bytes) away from grid[0][0]. What about the pointer-to-array? Each increment in the first index is a sizeof (int[5]) apart from the first. So in the case of a 4x5 array grid[1][0] is 5 * sizeof(int) (20-bytes) apart from grid[0][0].
So when attempting to access your array of arrays, using int**, beginning with grid[1][3] (or grid[1][4] on a 32-bit box) you are reading one-past the end of the 1st row of values. (you have offset by 8-bytes (one-pointer 8-bytes - skipping 2-int), placing you just before the 3rd integer in the 1st row, then offset 3 more integers placing you at what would be grid[0][5] one past the last value in the 1st row grid[0][4]. (this compounds with each row increment) The result is undefined and anything can happen.
When you pass the appropriate pointer-to-array, each increment of the row-index offsets by 20-bytes, placing you at the beginning of the next 1D array of values so iterating over each column remains within the bounds of that 1D array.
Think through it, and if you have further questions, just let me know and I'm happy to help further.
int** grid is a pointer to pointer to int. It lacks information of the array width.
With C99 or C11 onwards with optional variable length arrays:
// int islandPerimeter(int** grid, int gridSize, int gridColSize)
int islandPerimeter(int gridSize, int gridColSize, int grid[gridSize][gridColSize]) {
int perimeter=0;
for(int row=0;row<gridSize;++row) {
for(int col=0;col<gridColSize;++col) {
printf("%d ",grid[row][col]);
}
}
return perimeter;
}
Call with
islandPerimeter(4, 5, arr);
Try this
int islandPerimeter(int* grid, int gridSize, int gridColSize) {
int perimeter = 0, points = 4, i = 0;
for(int row=0; row < gridSize; ++row) {
for(int col = 0; col < gridColSize; ++col) {
printf("%d ",grid[row*gridColSize + col]);
}
}
return perimeter;
}
You will have to change the call to
islandPerimeter((int *)grid, 4, 5);
Let's say you wanted to leave your function as-is and instead change how the 2D array was initialized in main(or any other calling function). This is also what you would have to do if the array data was entered by a user or loaded from a file at runtime, so it's useful to know:
int main(void) {
const int ROWS = 4; //these don't have to be const;
const int COLS = 5;
const int data[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int** pointer_arr = malloc(ROWS * sizeof(int*)); //allocate space for each ptr
//error check
if (pointer_arr == NULL) {
printf("Unsuccessful ptr-ptrarray allocation attempt\n");
exit(0);
}
for (int i = 0; i < ROWS; ++i) {
pointer_arr[i] = malloc(COLS * sizeof(int)); //allocate space for each int
//error check with alternative indexing syntax (same as pointer_arr[i])
if (*(pointer_arr + i) == NULL) {
printf("Unsuccessful ptr-intarray allocation attempt\n");
exit(0);
}
}
//load each allocated int address space with an int from data:
for (int i = 0; i < ROWS ; ++i) {
for (int j = 0; j < COLS; ++j) {
pointer_arr[i][j] = data[ROWS * i + j];
}
}
//Now you can call your unaltered function and it will perform as expected:
islandperimeter(pointer_arr, ROWS, COLS);
return 0;
}
Under normal conditions (when the program doesn't terminate at once) note that you would then have to manually free all that allocated memory, or suffer a memory leak.
I try to get an array, an number and is_even bool variable from the user and return an only even numbers new array, else return only odd numbers array depending on is_even.
for example: the array {1,2,3,4} and is_even=1 will return {2,4} ,if is_even=0 the returned array will be {1,3}
as I get it I should allocate the array dynamically prior to passing it to a function. what I have done so far is.
I got stuck with the return. I checked whether the content pointed by p is even or odd but how do I erase cells?
#include <stdio.h>
#include <malloc.h>
int *new_array(int *p,int number,int is_even){
int j,i=0;
int counter=0;
if(is_even){
for(j=0;j<number;j++){
if(*(p+j)%2==0){
}
}
return p;
}
}
void main() {
int n,i,is_even;
int *p;
printf("enter number of elements");
scanf("%d",&n); rewind(stdin);
printf("hoose is_even 1 or 0");
scanf("%d",&is_even);rewind(stdin);
p=(int *)malloc(n* sizeof(int));
for(i=0;i<n;i++){
scanf("%d",p+i);
}
p=new_array(p,n,is_even);
for(i=0;i<n;i++){
printf("%4d",*(p+i));
}
}
Part of your problem is that you are not accounting for one of the pieces of information you need to convey to the caller: the effective number of integers in the returned array. Your print loop assumes the same number of elements as were originally read, but by the nature of the function, this will typically be too many.
You ask,
how do I erase cells?
, but "erasure" is not a thing you can do. You can overwrite array elements with different values, but you cannot make an individual array element cease to exist, especially not from the middle of an array. The usual idiom would be to put the elements you want to keep in the initial elements of either the original array or a new one, and return how many elements that is. In the case of a new array, you must also return a pointer to the (dynamically allocated) array. The function signature you present is not adequate, because it provides no good means to return the count of elements.
There is a number of ways to address that. A simple one would be to make number an in/out parameter, by passing a pointer to the number of elements instead of the number of elements value:
int *new_array(int *p, int *number, int is_even) {
// ... 'j' keeps a running count of the number of is_even elements
*number = j; // Write the final number of elements back to the caller
return p; // return the allocated array
}
The details of the implementation would need to change a bit to accommodate the change in type and usage of the number parameter, and also to fix bugs.
You might then call it like so:
p = new_array(p, &n, is_even);
... and afterward continue just as you already were doing.
You could place all of your even/odd numbers at the beginning of the array, realloc() the array for its new size, and send the value of its new length back in your return. but you will need your function to receive (int** Array) in order to change the pointer for the array
so function declaration could be int new_array(int **p ,int number ,int is_even)
The problem is not deleting the cells the problem is that when you delete them your arrays length is not the same anymore..
By the way you can also change the value of length and return the new add for the new array with int* new_array(int *p, int *number, int is_even)
I have a weird problem and I don't know the reason, so I can't think of a solution to fix it.
My problem:
I have a removeEntry function with a array of structs as parameter, but somehow this function doesn't work.
In an earlier version of my code, I declared my array of structs outside the main function (outside every function), and it worked then. But since I now create my array of struct in my main function, I have to give it as parameter, and now my removeEntry function doesn't work.
Code that isn't working:
void removeEntry(struct entry entries[])
{
int entryNumber;
int nrBytes = sizeof(entries);
int arrayLength = nrBytes / sizeof(entries[0]);
printf("\nEnter entry number to delete: ");
scanf("%d",&entryNumber);
while (scanfOnlyNumber(entryNumber) == false || entryNumber == 0 || entries[entryNumber].entry_number == 0)
{
printf("\nEnter a legit entry number to delete: ");
scanf("%d", &entryNumber);
// Tell the user that the entry was invalid
}
int i = 0;
for(i = entryNumber; i < arrayLength - 1; i++)
{
entries[i] = entries[i + 1]; //removes element and moves every element after that one place back.
}
updateEntryNumber(entries);
printf("\nEntry %d removed succesfully, and entry numbers updated!\n", entryNumber);
}
My teacher told me that my arraylength calculation doesn't work when I create my array of structs inside my main function (what I do now),
but I can't tell why it doesn't work. If anybody can explain that, then I might be able to fix my removeEnty problem by myself.
If anyone wants the working code (where I don't give my array as parameter, because I create my array outside every function), then tell me and I will post it.
Problem
When you pass an array to a function, you don't pass the entire array, instead you pass a pointer to the array. Hence, when you do int nrBytes = sizeof(entries); you're actually getting the size of pointer variable rather than the size of array.
Solution
Pass your array length along with a pointer to the array to the function, something like this:
void removeEntry(struct entry entries[], int arrayLength){
// your code
}
int nrBytes = sizeof(entries); // basically size of struct node *
int arrayLength = nrBytes / sizeof(entries[0]);
In this sizeof(entries) will give size of struct pointer , and not the array , and also in second statement , it wont correctly .
This is because array decays into pointer after passing it to function and referring it .
What you need to do is calculate number of elements in struct array in main and then pass it to the function .
void removeEntry(struct entry entries[],int arrayLength);
Calculate arrayLength in main as you do.
if you compile your example, you will probably see a warning like this one:
warning: sizeof on array function parameter will return size of 'entry *' instead of 'entry []' [-Wsizeof-array-argument]
As noted in the answer by V. Kravchenko, this suggests that nrBytes will contain merely the size of the pointer, while sizeof(entries[0]) returns the "true" size of the entire structure. Therefore, arrayLength will be most probably zero.
You should pass array's size to function, because int nrBytes = sizeof(entries); is always 4 or 8 (on x64 systems). It's just pointer's size.
int nrBytes = sizeof(entries);
Arrays of any type (even arrays of structs) decay into pointers when passed to a function. The lenght of this pointer is always fixed and gives no indication as to the lenght whatsoever. So pass the lenght with the function call.
In this toy code example:
int MAX = 5;
void fillArray(int** someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
(*someArray)[i] = blah[i]; // segfault happens here
}
int main() {
int someArray[MAX];
int blah[] = {1, 2, 3, 4, 5};
fillArray(&someArray, blah);
return 0;
}
... I want to fill the array someArray, and have the changes persist outside the function.
This is part of a very large homework assignment, and this question addresses the issue without allowing me to copy the solution. I am given a function signature that accepts an int** as a parameter, and I'm supposed to code the logic to fill that array. I was under the impression that dereferencing &someArray within the fillArray() function would give me the required array (a pointer to the first element), and that using bracketed array element access on that array would give me the necessary position that needs to be assigned. However, I cannot figure out why I'm getting a segfault.
Many thanks!
I want to fill the array someArray, and have the changes persist outside the function.
Just pass the array to the function as it decays to a pointer to the first element:
void fillArray(int* someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
someArray[i] = blah[i];
}
and invoked:
fillArray(someArray, blah);
The changes to the elements will be visible outside of the function.
If the actual code was to allocate an array within fillArray() then an int** would be required:
void fillArray(int** someArray, int* blah) {
int i;
*someArray = malloc(sizeof(int) * MAX);
if (*someArray)
{
for (i=0; i<MAX; i++) /* or memcpy() instead of loop */
(*someArray)[i] = blah[i];
}
}
and invoked:
int* someArray = NULL;
fillArray(&someArray, blah);
free(someArray);
When you create an array, such as int myArray[10][20], a guaranteed contiguous block of memory is allocated from the stack, and normal array arithmetic is used to find any given element in the array.
If you want to allocate that 3D "array" from the heap, you use malloc() and get some memory back. That memory is "dumb". It's just a chunk of memory, which should be thought of as a vector. None of the navigational logic attendant with an array comes with that, which means you must find another way to navigate your desired 3D array.
Since your call to malloc() returns a pointer, the first variable you need is a pointer to hold the vector of int* s you're going to need to hold some actual integer data IE:
int *pArray;
...but this still isn't the storage you want to store integers. What you have is an array of pointers, currently pointing to nothing. To get storage for your data, you need to call malloc() 10 times, with each malloc() allocating space for 20 integers on each call, whose return pointers will be stored in the *pArray vector of pointers. This means that
int *pArray
needs to be changed to
int **pArray
to correctly indicate that it is a pointer to the base of a vector of pointers.
The first dereferencing, *pArray[i], lands you somewhere in an array of int pointers, and the 2nd dereferencing, *p[i][j], lands you somewhere inside an array of ints, pointed to by an int pointer in pArray[i].
IE: you have a cloud of integer vectors scattered all over the heap, pointed to by an array of pointers keeping track of their locations. Not at all similar to Array[10][20] allocated statically from the stack, which is all contiguous storage, and doesn't have a single pointer in it anywhere.
As others have eluded to, the pointer-based heap method doesn't seem to have a lot going for it at first glance, but turns out to be massively superior.
1st, and foremost, you can free() or realloc() to resize heap memory whenever you want, and it doesn't go out of scope when the function returns. More importantly, experienced C coders arrange their functions to operate on vectors where possible, where 1 level of indirection is removed in the function call. Finally, for large arrays, relative to available memory, and especially on large, shared machines, the large chunks of contiguous memory are often not available, and are not friendly to other programs that need memory to operate. Code with large static arrays, allocated on the stack, are maintenance nightmares.
Here you can see that the table is just a shell collecting vector pointers returned from vector operations, where everything interesting happens at the vector level, or element level. In this particular case, the vector code in VecRand() is calloc()ing it's own storage and returning calloc()'s return pointer to TblRand(), but TblRand has the flexibility to allocate VecRand()'s storage as well, just by replacing the NULL argument to VecRand() with a call to calloc()
/*-------------------------------------------------------------------------------------*/
dbl **TblRand(dbl **TblPtr, int rows, int cols)
{
int i=0;
if ( NULL == TblPtr ){
if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*))))
printf("\nCalloc for pointer array in TblRand failed");
}
for (; i!=rows; i++){
TblPtr[i] = VecRand(NULL, cols);
}
return TblPtr;
}
/*-------------------------------------------------------------------------------------*/
dbl *VecRand(dbl *VecPtr, int cols)
{
if ( NULL == VecPtr ){
if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl))))
printf("\nCalloc for random number vector in VecRand failed");
}
Randx = GenRand(VecPtr, cols, Randx);
return VecPtr;
}
/*--------------------------------------------------------------------------------------*/
static long GenRand(dbl *VecPtr, int cols, long RandSeed)
{
dbl r=0, Denom=2147483647.0;
while ( cols-- )
{
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
r = sqrt(-2.0 * log((dbl)(RandSeed/Denom)));
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
*VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom));
VecPtr++;
}
return RandSeed;
}
There is no "array/pointer" equivalence, and arrays and pointers are very different. Never confuse them. someArray is an array. &someArray is a pointer to an array, and has type int (*)[MAX]. The function takes a pointer to a pointer, i.e. int **, which needs to point to a pointer variable somewhere in memory. There is no pointer variable anywhere in your code. What could it possibly point to?
An array value can implicitly degrade into a pointer rvalue for its first element in certain expressions. Something that requires an lvalue like taking the address (&) obviously does not work this way. Here are some differences between array types and pointer types:
Array types cannot be assigned or passed. Pointer types can
Pointer to array and pointer to pointer are different types
Array of arrays and array of pointers are different types
The sizeof of an array type is the length times the size of the component type; the sizeof of a pointer is just the size of a
pointer