I have an array named record[10] whose type is a table structure, say { int, int, long, long,char}
I have a function to which I want to pass the address of this array which gets called in a loop:
for(i = 0 ; i<10; i++)
{
// internal resolution will be *(record + i) will fetch an address
function(record[i]);
}
I'm confused as to why it is not working. I know it is related to basics.
It started working with
for(i = 0 ; i<10; i++)
{
// then why do I need to pass this address of address here
function(&record[i]);
}
*(record + i) is not in fact an address. record is an address, and so is (record + i), but *(record + i) is the value stored at the address represented by (record + i). Therefore, calling function(record[i]) is the same as function(*(record + i)), which will pass the value of the array element to the function, not a pointer.
The syntax &record[i] is not taking the address of an address. It is taking the address of record[i], which is an object. The braces have a higher precedence than the ampersand, so &record[i] is equivalent to &(record[i]). You can think of it as expanding to &(*(record + i)) and then simplifying to (record + i).
Update:
To address your question from the comment, an array "decays" into a pointer if you reference the name of the array by itself. If you add square brackets [], you will get a value from within the array. So, for your example, say you have an array of structures:
struct A {
...
char abc[10];
...
} record[10];
Then, you would have:
record[i] - an object of type struct A from the record array
record[i].abc - the abc array inside a particular record object, decayed to a pointer
record[i].abc[k] - a specific character from the string
&record[i].abc[0] - one way of creating a pointer to the string
The notation record[i]->abc that you mention in your comment cannot be used, since record[i] is an object and not a pointer.
Update 2:
In regards to your second comment, the same rules described above apply regardless of how you nest the array within a structure (and whether you access that structure directly or through a pointer). Accessing an array using arrayname[index] notation will give you an item from the array. Accessing an array using arrayname notation (that is, using the array name by itself) will give you a pointer to the first element in the array. If you need more details regarding this phenomenon, here are a couple of links that explain arrays and the way that their names can decay into pointers:
http://boredzo.org/pointers/
http://www.ibiblio.org/pub/languages/fortran/append-c.html
http://c-faq.com/aryptr/index.html
You're saying two different things in your question. First, you say you want to pass the address of the array, but in the code you appear to be trying to pass the address of a particular element. One of the features of C is that an array will automatically turn into pointer to the array's first element when you use it in certain contexts. That means these two calls are 100% equivalent:
function(array);
function(&array);
To get the address of a particular array element, you can do two things. One is as you've shown above:
function(&array[10]);
And the second is just do the pointer arithmetic directly:
function(array + 10);
In the first case the & is required, since as you mentioned in your question the [] causes the pointer to be dereferenced - the & undoes that operation. What you appear to be confused about are the real semantics of the [] operation. It both does pointer arithmetic and then dereferences the result - you're not getting an address out of that. That's where the & comes in (or just using array + 10 directly).
You are passing by value which means a copy of the variable is sent to the function. In the 2nd case you are passing by reference.
In the second case you are directly modifying the contents at the address of the array plus index.
Check this simple example to know the exact difference.
Your function's signature is probably
void function(table *); // argument's type is pointer to a table
When you pass record[i], you pass a table object.
In order to pass a pointer to a table, you have to pass &record[i], like you did.
Your function is expecting a pointer to the structure. This arguement can be an individual instance of that structure or it could be an element in the array of the give structure. Like
struct myStruct {
int a, b;
long cL, dL;
char e;
} struc1, struc2, record[20];
and function's prototype will be
function( struct myStruct *ptr);
Now you can pass the structure to function:
function( &struct1 );
// or
function( &record[ index] );
Now your confusion arises because of the misconception that syntax array[i] can also be treated as a pointer like we can do with the name of the array.
record - name of the array- gives the address of the first member of the array, (pointers also point to memory addresses) hence it can be be passed to the function. But record[index], it is different.
Actually, when we write record[ index] it gives us the value placed there which is not a pointer. Hence your function which is accepting a pointer, does not accept it.
To make it acceptable to the function, you will have to pass the address of the elements of the array i.e
function( &record[ index ] );
Here & operator gives the address of the elements of the array.
Alternatively, you can also use:
function( record + index );
Here, as we know record is the address of the first element, and when we add index in it, it gives the address of the respective element using pointer arithmetic.
Hope it was helpful.
Related
Inspired this quiestion .
Why does -
void display(int p[][SIZE]) // allowed
and
void display(int p[][]) // not allowed
?
Because arrays decay to pointers when passed to a function. If you do not provide the cardinality of the second dimension of the array, the compiler would not know how to dereference this pointer.
Here is a longer explanation: when you write this
p[index]
the compiler performs some pointer arithmetic to find the address of the element that it needs to reference: it multiplies index by the size of p's element, and adds it to the base address of p:
address = <base address of p> + index * <size of p's element>
When you try passing an array like this, p[][], the compiler knows only the base address of p, but not the size of its element. It is in order for the compiler to know the size of p's element that you need to provide the cardinality of the second dimension.
Because a 2D array is stored row wise and hence the function needs the number of columns so that it knows when the next row begins.
That's because caculations in pointers requires that.
When p points to 2 dimentional array that's size is SIZE this operation p+=3 is calculated this way:
if the value of p is a constant equal ADRESS
p receive this value ADRESS + 3*SIZE.
That's because arithmitic in pointers is different from arithmitic in real numbers. This calculation can't be done without knowing the size of the array.
The name of an array is a synonym for the address of the first element of the array, so why can't this address be set to NULL? Is it a language rule to prevent a memory leak?
Also, when we pass an array to a function, it's behavior changes and it becomes possible to set it to NULL.
I don't understand why this occurs. I know it has something to do with pointers, but I just can't wrap my mind around it.
Example:
void some_function(char string[]);
int main()
{
char string[] = "Some string!";
some_function(string);
printf("%s\n", string);
return 0 ;
}
void some_function(char string[])
{
string = NULL;
}
Output: Some string!
I read that when an array is passed into a function, what's actually passed are pointers to each element, but wouldn't the name of the array itself still be a synonym for the address of the first element? Why is setting it to NULL here even allowed, but not in the main function?
Is it at all possible to set an array to NULL?
An array is not a pointer - the symbol string in your case has attributes of address and size whereas a pointer has only an address attribute. Because an array has an address it can be converted to or interpreted as a pointer, and the language supports this implicitly in a number of cases.
When interpreted as a pointer you should consider its type to be char* const - i.e. a constant pointer to variable data, so the address cannot be changed.
In the case of passing the array to a function, you have to understand that arrays are not first class data types in C, and that they are passed by reference (i.e. a pointer) - loosing the size information. The pointer passed to the function is not the array, but a pointer to the array - it is variable independent of the original array.
You can illustrate what is effectively happening without the added confusion of function call semantics by declaring:
char string[] = "Some string!";
char* pstring = string ;
then doing:
pstring = NULL ;
Critically, the original array data cannot just "disappear" while it is in scope (or at all if it were static), the content of the array is the variable, whereas a pointer is a variable that refers to data. A pointer implements indirection, and array does not. When an array is passed to a function, indirection occurs and a pointer to the array is passed rather than a copy of the array.
Incidentally, to pass an array (which is not a first class data type) by copy to a function, you must wrap int within a struct (structs in C are first class data types). This is largely down to the original design of C under constraints of systems with limited memory resources and the need to to maintain compatibility with early implementations and large bodies of legacy code.
So the fact that you cannot assign a pointer to an array is hardly the surprising part - because to do so makes little sense. What is surprising perhaps is the semantics of "passing an array" and the fact that an array is not a first class data type; leading perhaps to your confusion on the matter.
You can't rebind an array variable. An array is not a pointer. True, at a low level they are approximately similar, except pointers have no associated dimension / rank information.
You cant assign NULL to the actual array (same scope), but you can assign to a parameter since C treats it like a pointer.
The standard says:
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’,
So in the function the NULL assignment is legal.
I am referring a book Named "Let Us c" By Yashwant Kanetkar.
I am a little confused about this example where he assigns a base address to a pointer.
Example:
int x[10] = {1,2,3,4,5,6,7,8,9,10,11};
int *p = x; // base address of x assigned to *p
//************//
int z[10] = {1,2,3,4,5,6,7,8,9,10,11};
int *q = &z[0]; // base address of z assigned to *q
If both have the same functionality then why is different notation used? Is there any other reason for doing this?
When you use the name of an array in an assignment, like in the first case, the array decays to a pointer to the address of the first element.
In the second case, the expression z[0] gives you the first element of the array by value and when you prepend an ampersand & to the expression, you get the address of that element which renders the same result of the first case.
Both are effectively same. By using the base index, you can iterate through the memory allocated for the array. In this case accessing a[10]; is not correct since array was defined to hold maximum of 10 elements.
The second notation is mostly used to assign the address of the particular element,, &x[n]
The two different notations for the same result illustrate that x, the array, is truly just a pointer while x[0], an element, is an actual value. This is just one of the many examples of multiple ways of saying the same thing in C (kind of like English).
My question is both specific to an assignment I'm working on and conceptual about the relationship between pointers and arrays. I'm writing a hash table in the form of an array of pointers to sorted lists. I've created a struct to define a type for the hash table and the number of elements in the table is defined in a macro. Since the size of the table is variable, the struct needs to contain a pointer to the table itself - a pointer to an array of pointers. My problem revolves around the idea that a pointer to some data type is the same as the label for the first element of an array of that data type.
I have a data type SortedList. As I understand things, SortedList* can be interpreted as either a pointer to a single SortedList or as a pointer to the first element of an array of SortedList's. Expanding on that, SortedList** can be an array of SortedList pointers and SortedList*** can be a pointer to that array. This is what I have in my hash table struct. My first question is, is my understanding of this correct?
In the function that creates the hash table I have this:
SortedList** array;
if ((array = calloc(size,sizeof(SortedList*))) == NULL) {
// error allocating memory
printf("Memory Error\n");
return NULL;
}
table->arrayPtr = &array;
So array is intended to be my array of SortedList pointers and arrayPtr is the SortedList*** type in my hash table struct. I'm using calloc because I think it will initialize all of my pointers to NULL. Please let me know if I'm mistaken about that. This all compiles with no errors so, as far as I know, so far
so good.
I have function that inserts data into the table that first checks to see if this pointer has not been used already by checking to see if it points to NULL, if not, it creates a SortedList for it to point to.
int i = index->hashFunc(word);
SortedList*** table = index->arrayPtr;
if (*(table +i) == NULL){
return 0;
}
So it seems to me that dereferencing (table +i) ought to give me a SortedList** - the ith element in an array of SortedList pointers - which I can then check to see if it's set to NULL. Unfortunately, the compiler disagrees. I get this error:
error: invalid operands to binary == (have ‘struct SortedList’ and ‘void *’)
So somewhere along the line my reasoning about all this is wrong.
You might need to read up a little bit more on arrays and pointers in C because I don't think you completely grasp the concept. I could be wrong but I doubt you'd need a three level pointer to achieve what you're trying to do; I think you might be confusing yourself and thinking that if you want to point to an array's data you need to point to the actual array (&array), which is essentially a pointer itself. Drawing a picture can also really help to visualise what's going on in memory.
An array is merely a block of sequential data, where the variable's name in C (without any [ ], which would get an element from the array) points to the first element in the array. The two lines in the example below are equivalent (where array is obviously an array):
int *p_array;
p_array = array; /* equivalent */
p_array = &array[0]; /* equivalent */
You could then use p_array exactly the same way as if you were to use array, ie.
p_array[3] == array[3]
The unnecessary thing that some people might do when they're learning is have a pointer to a pointer to an array (which I think is what you're doing):
int **p_p_array = &array;
And then to access the elements of array they would have to dereference the pointer and then use array notation to specify the element in the array:
*p_p_array[3] == array[3]
What we've actually done here is store the memory address of array (which itself is a pointer to the first element), which we then have to dereference to get to the first element, and then we move 3 positions forward to get to the fourth element (array[3]).
In the first example it's so much simpler and more logical, since we're storing a pointer to the first element in the array and having the pointer act in the same way as our initial array variable.
I recommend you draw out what you're trying to do on a piece of paper/whiteboard to see what you're doing wrong and it may then become obvious how to properly implement it the right way. My whiteboard is one of my best tools when I'm coding something.
Consider the following statements:
int *pFarr, *pVarr;
int farr[3] = {11,22,33};
int varr[3] = {7,8,9};
pFarr = &(farr[0]);
pVarr = varr;
At this stage, both pointers are pointing at the start of each respective array address. For *pFarr, we are presently looking at 11 and for *pVarr, 7.
Equally, if I request the contents of each array through *farr and *varr, i also get 11 and 7.
So far so good.
Now, let's try pFarr++ and pVarr++. Great. We're now looking at 22 and 8, as expected.
But now...
Trying to move up farr++ and varr++ ... and we get "wrong type of argument to increment".
Now, I recognize the difference between an array pointer and a regular pointer, but since their behaviour is similar, why this limitation?
This is further confusing to me when I also consider that in the same program I can call the following function in an ostensibly correct way and in another incorrect way, and I get the same behaviour, though in contrast to what happened in the code posted above!?
working_on_pointers ( pFarr, farr ); // calling with expected parameters
working_on_pointers ( farr, pFarr ); // calling with inverted parameters
.
void working_on_pointers ( int *pExpect, int aExpect[] ) {
printf("%i", *pExpect); // displays the contents of pExpect ok
printf("%i", *aExpect); // displays the contents of aExpect ok
pExpect++; // no warnings or errors
aExpect++; // no warnings or errors
printf("%i", *pExpect); // displays the next element or an overflow element (with no errors)
printf("%i", *aExpect); // displays the next element or an overflow element (with no errors)
}
Could someone help me to understand why array pointers and pointers behave in similar ways in some contexts, but different in others?
So many thanks.
EDIT: Noobs like myself could further benefit from this resource: http://www.panix.com/~elflord/cpp/gotchas/index.shtml
The difference is because for farr++ to have any effect, somewhere the compiler would need to store that farr will evaluate to the address of the second element of the array. But there is no place for that information. The compiler only allocates place for 3 integers.
Now when you declare that a function parameter is an array, the function parameter won't be an array. The function parameter will be a pointer. There are no array parameters in C. So the following two declarations are equivalent
void f(int *a);
void f(int a[]);
It doesn't even matter what number you put between the brackets - since the parameter really will be a pointer, the "size" is just ignored.
This is the same for functions - the following two are equivalent and have a function pointer as parameter:
void f(void (*p)());
void f(void p());
While you can call both a function pointer and a function (so they are used similar), you also won't be able to write to a function, because it's not a pointer - it merely converts to a pointer:
f = NULL; // error!
Much the same way you can't modify an array.
In C, you cannot assign to arrays. So, given:
T data[N];
where T is a type and N is a number, you cannot say:
data = ...;
Given the above, and that data++; is trying to assign to data, you get the error.
There is one simple rule in C about arrays and pointers. It is that, in value contexts, the name of an array is equivalent to a pointer to its first element, and in object contexts, the name of an array is equivalent to an array.
Object context is when you take the size of an array using sizeof, or when you take its address (&data), or at the time of initialization of an array. In all other contexts, you are in value context. This includes passing an array to a function.
So, your function:
void working_on_pointers ( int *pExpect, int aExpect[] ) {
is equivalent to
void working_on_pointers ( int *pExpect, int *aExpect ) {
The function can't tell if it was passed an array or a pointer, since all it sees is a pointer.
There are more details in the answers to the following questions:
type of an array,
sizeof behaving unexpectedly,
Also see this part of C for smarties website, which is very well-written.
Trying to increment farr or varr fails because neither one is a pointer. Each is an array. The name of an array, when evaluated by itself (except as the operand of the sizeof or address-of operator) evaluates to a value (an rvalue) that's of the correct type to be assigned to a pointer. Trying to increment it is a bit like trying to increment 17. You can increment an int that contains the value 17, but incrementing 17 itself won't work. The name of an array is pretty much like that.
As for your second part, it's pretty simple: if you attempt to declare a function parameter of array type, the compiler silently "adjusts" it to a pointer type. As such, in your working_on_pointers, aExpect and pExpect have exactly the same type. Despite the array-style notation, you've defined aExpect as having type 'pointer to int'. Since the two are the same, it's entirely expected that they'll act the same.
Have a look at this answer I posted in relation to differences between pointers and arrays here on SO.
Hope this helps.
okay, i may be wrong. but arrays and pointers can be used alternately.
int * ptr = (int *)malloc(2* sizeof(int));
ptr[0]=1;
ptr[1]=2;
printf ("%d\n", ptr[0]);
printf ("%d\n", ptr[1]);
here i declared a pointer and now i am treating it as array.
moreover:
As a consequence of this definition,
there is no apparent difference in the
behavior of the "array subscripting"
operator [] as it applies to arrays
and pointers. In an expression of the
form a[i], the array reference "a"
decays into a pointer, following the
rule above, and is then subscripted
just as would be a pointer variable in
the expression p[i] (although the
eventual memory accesses will be
different, as explained in question
2.2). In either case, the expression x[i] (where x is an array or a
pointer) is, by definition, identical
to *((x)+(i)).
reference: http://www.lysator.liu.se/c/c-faq/c-2.html
you need to understand the basic concept of arrays.
when you declare an array i.e
int farr[]
you are actually declaring a pointer with this declaration
const int * farr
i.e; a "constant" pointer to integer. so when you do farr++ you are actually trying to add up to a pointer which is constant, hence compilers gives you an error.
if you need to understand, try to declare a pointer with the above declaration and you would not be able to do the arithmetic which are legal on normal pointers.
P.S:
its been quiet a while i have coded in C so i am not sure about exact syntax. but bottom line is the difference between a pointer and a constant pointer.