I've been learning C for about 2 months, still a novice:(
I know there are other similar questions on this site. I've read them, but still couldn't really understand, so here I am. Below is my code:
//naming my structure as ball
typedef struct ball_room {
int enter;
int exit;
} ball;
//I've omitted some irrelevant details for brevity
int i, n, max;
scanf("%d", &n);
ball person[n];
.../*assign values to ball.enter and ball.exit with user input*/
max = 1;
for (i = 0; i < n; i++)
if (ball_room(person, person[i].enter, n) > max)
max = ball_room(person, person[i].enter, n);
printf("%d\n", max);
return 0;
}
and below is my function receiving the array:
//This function returns the number of people in the ballroom
//when b[j](person[j] in "main") enters
int ball_room(ball *b, int i, int n)
{
int people = 0, j;
for (j = 0; j < n; j++)
if (b[j].enter <= i && b[j].exit > i)
people++;
return people;
}
my question is that why is it b[j].enter instead of b[j]->enter, which my compiler wouldn't accept?
In my limited experience, when manipulating structure itself (the object), I use . to go inside the structure, and when it's a pointer (the address), I use -> (hope this is correct.)
And in this case, I pass the array to function using ball *b, which represent the address of person[0], so I can access the whole array. But shouldn't ball *b be in the form of a pointer and therefore I should use -> to access its content? It's just an address that I pass to the function.
This is my first time doing something with an array of structures, please help me get this clear, thank you!
Given ball *b, b[j] is an element from the elements that b points to. Thus b[j] is not a pointer; it is a struct. Since it is a struct, you use . to refer to members in it.
The definition of b[j] in the C standard is that it is *((b)+(j)). So it takes the pointer b, moves j elements beyond it, and then applies *.
Since * is already applied in b[j], you do not need ->, just ..
you use . instead of -> because of this declaration of parameters:
int ball_room(ball *b, int i, int n)
b is expected to be pointer to data with type ball, so you can access it in various ways:
array way: e.g. b[5].somefield = 15 - you use dot here, because if b is of type ball *, it means that b is pointer OR it is array of objects with type b, if it's array of objects with type b (which is your case) you use . to access fields of object
pointer way: e.g. (b+5)->somefield = 15 - it will do exactly same thing as code above, but you will access data in pointer way
In C/C++ an array devolves into the address of it's first member. So when you pass the array to ball_room what actually gets passed is &ball[0].
Now inside ball_room the reverse happens. b is a pointer to ball. But here you use it as an array b[j]. So it un-devolves back into an array of structs. So what b[j] gives you is the struct and not a pointer to a struct. Consequently you access it using . instead of ->.
You can also use (b + j)->somefield. Or for even more fun how about writing j[b].somefield. The later being a really confusing left-over from the eraly compiler days when a[b] truly got turned into *(a + b) internally.
For explanation of the current issue, see Eric's answer; in some of the answers given so far there is dangerous wording applied, so just to make clear: When do we have an array and when a pointer???
Consider the following:
int a[7];
As long as we can refer to a directly, we still have an array and can use any operations that are valid on, e. g. getting size:
size_t n = sizeof(a); // size in bytes, not ints, i. e. 7*sizeof(int)
You can pass arrays to functions or even do pointer arithmetics on:
f(a);
a + 1;
In both cases, the array "decays" to a pointer, though, and the result is a pointer as well. Be aware that you can assign new values to a pointer, but not to an array itself (you can assign new values to the array's elements, directly or via pointer), so you cannot do things like ++a either.
When an array decays to a pointer, it gets a pointer to its first element:
int* ptr = a;
int* ptr = &*a; // only pointers can be dereferenced -> a decays!
int* ptr = &a[0]; // short for &*(a + 0)...
All result in exactly the same; however, the following is invalid:
int* ptr = &a;
Taking the address of an entire array actually is possible, but the resulting pointer is not of type "pointer to element" nor of type "pointer to pointer to element" (int** in the example), but of type "pointer to array of specific size". Syntax for is ugly, though, but the following would be legal again:
int(*aptr)[7] = &a;
You need to read: if I dereference ptr, I get int[7]...
Once decayed, there is only a pointer to the array left (more precisely: to one of the array elements, directly after decaying, to the first; array and first element always share the same address, so, although of different type, both pointers ptr and aptr from above hold exactly the same value). Pointers can be moved around within the array, but they do not hold as much information as the array itself, especially, the array size gets lost. This is why one needs to pass the array's length together with the pointer to functions (if needed; another variant is a sentinel value denoting the array end such as the terminating null character in strings or the null pointer following the string arguments in main's arguments list):
int a[7];
f(a, sizeof(a)/sizeof(*a)); // division: sizeof is in bytes, dividing by size
// of first element gives number of elements
Possibly with f as:
void f(int b[], size_t n)
// ^^^^^^^ in function parameter lists, just alternative syntax for int* b !!!
// however, we can show more explicitly that we expect a pointer
// to an array this way...
{
size_t m = sizeof(b); // as b is a POINTER, gives the constant (but hardware specific!)
// size of a pointer (on typical modern 64-bit hardware 8 bytes),
// no matter what size of the array being pointed to is!!!
while(n)
{
*b++ = n--;
// ^^ advances pointer, NOT array!
}
}
Hope this helps to avoid confusion.
In C, the array name is a pointer to array’s first element, hence your function declaration has name ball *band works when you pass a ball[] instance.
Try dynamically allocating the memory by using malloc() and passing that pointer to your function.
Related
I am confused about a notation in C when I have a pointer variable f pointing to a struct X defined as:
struct Y {
int d;
struct X *e;
};
struct X {
int *a;
int b[4];
struct Y c;
};
Then I have this:
f->c.e->c.e[0].a[0]
The thing I don't understand is the part c.e[0].a[0].
I am not sure what is c.e[0] and then also what is c.e[0].a[0]. (also not sure whether c.e[0] is 20-offset from the starting address of a struct X). Assuming here pointer is 4 bytes, integer is 4 bytes. So int *a + int b[4] + int d = 20 offset?
is it the meaning of f->c.e->c.e[0]? is there f->c.e->c.e[3]? f->c.e->c.e[4]? f->c.e->c.e[5]?
I am confused because usually for a pointer variable say k, I always see k->x, k->y, k->l to refer to the variables within a struct when the variable k is pointing to the struct variable. However in this case, I see the notation of c.e->c.e[0].a[0]. Is e[0].a[0] valid? I guess e[0] is not a pointer then, since if it is a pointer e[0] must always use the -> notation to refer to a variable within a struct it pointing to, but since it uses (dot .) instead of (arrow ->), e[0].a[0] so I guess e[0] in this case is not a pointer right?
then I am little confused as to what is the meaning of c.e[0].a[0] in my given struct X, struct Y, and the given pointer variable f here.
c.e is a pointer to a struct X, so c.e[0] is the struct X pointed to by c.e.
If c.e is a pointer to the first element of an array of 4 struct Y, the 4 elements of this array could be referred to as c.e[0], c.e[1], c.e[2] and c.e[3].
For all pointers p, p[0] is equivalent to *p or *(p + 0) (or even 0[p]).
In this case, f->c.e->c.e[0].a[0] is equivalent to f->c.e->c.e->a[0] and *f->c.e->c.e->a. Which syntax is used is a question of style and readability. The array syntax using [] is usually more readable when the index is or can be different from zero, in case of pointers to single objects, the -> syntax is preferred.
The actual implementation details, such as pointer and integer sizes is irrelevant here, but bear in mind that the offset of a member in a structure may be affected by alignment constraints: for example in most current 64-bit systems, an int still has 4 bytes but a pointer uses 8 bytes, so the offset of e in struct Y must be aligned on a multiple of 8, hence is 8, not 4. 4 padding bytes are inserted between d and e. Note also that if d is meant to store the number of elements in the array pointed to by e, it should probably be defined with type size_t.
The confusion comes from the multiple ways of using pointers in C.
Declaring a simple array goes as follow:
<type> <name>[<size>];
// More concretely
int array_of_ints[5];
// Accessing its elements is straightforward
array_of_ints[0] = 42;
But what if you can't know the size in advance? You'd have to allocate memory with e.g. malloc which gives you a pointer to the beginning of the array:
int * array_of_ints = malloc(sizeof(int) * 5);
// Access its elements the same way as arrays declared on the stack
array_of_ints[0] = 42;
How come the same syntax can be used for both types (int[5] vs. int *)?
This is because under the hood the compiler treats it the exact same way. The name of the array is actually a pointer to its first element, as we can see here:
void foo(int * array)
{
printf("%d\n", *array); // *array and array[0] are interchangeable
}
int bar()
{
int array[5];
array[0] = 42;
foo(array);
}
So an array can be decayed into a pointer. And the language lets you use the [] operator because the compiler actually translates it using pointer arithmetic:
array[0] is the same as *array but, more precisely, the same as *(array + 0).
So how do you know if you have a pointer to a single value or a pointer to a value that's the first value of an array? Well, without context, you can't. From an isolated function's perspective, you can't know if taking a char * parameter means it is a string argument or a pointer to a single char variable. It's up to the developers to make it clear, either by passing the size of the array along with it, or naming the variable correctly (char * str vs. char * c for instance), writing documentation, etc.
I’m taking a C class on Udemy. Unfortunately the instructor isn’t replying to my question so I thought I’d try this site. My assumption is that it is probably fairly common when developing a program to not know how many elements may be part of an array. When initializing an array the instructor recommends not specifying a size but to let the compiler do it.
Example: int array[ ] = {2,3,4,5,6,7,8};
Obviously, using this method there is no index to use to terminate looping. According to “C Primer Plus” by Stephen Prata the element after the last element in the array is a valid pointer location:
(pg. 406) - C guarantees that when it allocates space for an array, a
pointer to the first location after the end of the array is a valid
pointer.
If I’m using pointer notation (array++) to loop through the array, what condition can I use to terminate the looping? Is there a value in that location after the final element that I can use? Is that value always the same or does it change depending on the type of array?
In C pointers are signed. That has consequences dealing with array-like data structures where you might:
while (a <= a+last) {
...
a++;
}
if the index one beyond the end of a could have a change of sign, then that code could fail. Idiomatic C does not suggest the above; but it needs to be preserved, thus this limitation.
In system code, it is possible that you deal with allocations that do not conform to this, thus you should try to work with the idiomatic:
while (a < a+len) {
...
a++
}
So, for your exact question:
for (size_t i = 0; i < sizeof array/sizeof array[0]; i++) {
...
}
or
for (int *p = array; p < array + sizeof array / sizeof array[0]; p++) {
...
}
Your basic idea (looping through an array using pointers) is sound; however, there are a number of points in your question that need some attention.
Is there a value in that location after the final element that I can use? Is that value always the same or does it change depending on the type of array?
Yes, there is a (almost certainly) some value in that location, but it's not something you can ever use! The pointer to the 'one-past-the-end' element is valid only for use in pointer arithmetic or comparison operations; attempting to dereference it (to read the value at that address) is undefined behaviour.
You can get that 'one-past-the-end' pointer by adding the number of elements in the array to the address of the array's first element (or the array 'name' itself). The idiomatic way to get the number of elements in an array is to divide the size of the entire array by the size of its first element. So, for your array, we can declare and initialize our "end pointer" like this, using the sizeof operator:
int* end = array + sizeof(array) / sizeof(*array);
// int* end = array + sizeof array / sizeof *array; // Alternative form: "()" optional
Another important point: In your question you mention using array++ to loop through your array variable. You cannot do this, because array isn't actually a (modifiable) pointer variable – it's the name of a variable (an array) whose location is fixed at the point when main (or whatever function it is declared inside) is entered. Instead, you will need to copy the address of the array into another int* pointer, and increment that in the loop.
With those points in mind, here's an illustrative example of how you can loop through your array using a pointer:
#include <stdio.h>
int main(void)
{
int array[] = { 2,3,4,5,6,7,8 };
int* end = array + sizeof(array) / sizeof(*array);
for (int* p = array; p < end; ++p) {
// Note that, when we reach p == end, the loop will not run, so ...
printf("%d\n", *p); // ...we never attempt the *p operation on that
}
return 0;
}
A couple of other points of clarification:
The int* p = array assignment works (and is perfectly valid C) because an array variable name can readily decay into a pointer to its first element (as it will if you pass that array as an argument to a function, for example). See: What is array to pointer decay?
Because of that last point above, you cannot use the sizeof(a)/sizeof(*a) paradigm to determine the size of an array in a function it is passed to as an argument; in such cases, you need to pass the array's size as an additional argument. See: How do I determine the size of my array in C?
I am mixed up on my pointers and references. I want to create a pointer in a main function and set it to null. I would like to pass that pointer to another function that creates an array on the heap, fills it, and returns the size of the created array.
I tried to find another article about this topic but failed to find one that allocated memory from within the function. The example code below illustrates the concept but I am not writing a program to accomplish any specific task.
int fillarray(/* pointer to an array */){
// malloc the array to size n
// fill array with n elements
return n;
}
int main(){
int* array = NULL;
int size = fillarray(/* pass the pointer by reference */);
for(int i = 0; i < size; i++) printf("%d\n", array[i]);
free(array);
return 0;
}
UPDATE:
Thank you all for your comments. I learned a ton about pointers working through this problem. The code below accomplishes what I need it to. Thank you #Lundin. Your answer led me to the actual solution. Thank you #ssd as well. Your visual helped me gain some intuition on what I was looking at in the code.
int fillarray(int** array){
*array = (int*)malloc(2 * sizeof(int));
(*array)[0] = 0;
(*array)[1] = 1;
return 2;
}
int main(){
int* array = NULL;
int size = fillarray(&array);
for(int i = 0; i < size; i++) printf("%d\t", array[i]);
return 0;
}
Strictly speaking there are no "references" in C, everything is passed by value. Although the term "pass by reference" is language agnostic and really just means pass an address to the data. (C++ has a language concept called references, but it's really just glorified read-only pointers.)
So to achieve what you want, you have to pass the address of the pointer itself. That way, the function can access the pointer and set it to point at a new address. Thus declare the function as int fillarray (int**)call the function as fillarray(&array). The result of malloc needs to be assigned to where the pointer-to-pointer points at - it points at the address of the original pointer declared variable in main().
As for allocating a variable size, you will have to add an additional plain integer parameter to the function for that.
I do agree & consent Lundin's answer but to be more conceptual, I'll add the drawing below, for I had the same pain in the past understanding pointers.
The first integer pointer below (int *a) is at memory address 4c4b40 and its value is set to zero (which means this pointer a is set to null).
The second integer pointer (int *b) is at memory address 4c4b48 and its value is set to 4c4b58 (which means, this pointer points to memory address 4c4b58 with a length of integer). If that address corresponds to variable int x = 16 (hexadecimal 10 is equal to 16), then dereferencing pointer b will give you an integer value of 16 (*b = 16 because x = 16).
The third memory is another character string pointer, which points to a memory address somewhere down below.
Returning to the answer:
If you are to change the address of the first pointer (a) in order to point to the variable x, then the function you're calling needs to receive the address of the pointer (not the pointer, itself); i.e. &a instead of a, which corresponds to 4c4b40. The function called will receive the address 4c4b40 as a memory address and change its value from 000000 to 4c4b58. The function decoration, of course, will contain an int **; for, if an integer pointer is an int *, a pointer to a pointer will be an int **.
I started learning C recently, and I'm having a problem understanding pointer syntax, for example when I write the following line:
int ** arr = NULL;
How can I know if:
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
Isn't it all the same with int ** ?
Another question for the same problem:
If I have a function that receives char ** s as a parameter, I want to refer to it as a pointer to an array of strings, meaning a pointer to an array of pointers to an array of chars, but is it also a pointer to a pointer to a char?
Isn't it all the same with int **?
You've just discovered what may be considered a flaw in the type system. Every option you specified can be true. It's essentially derived from a flat view of a programs memory, where a single address can be used to reference various logical memory layouts.
The way C programmers have been dealing with this since C's inception, is by putting a convention in place. Such as demanding size parameter(s) for functions that accept such pointers, and documenting their assumptions about the memory layout. Or demanding that arrays be terminated with a special value, thus allowing "jagged" buffers of pointers to buffers.
I feel a certain amount of clarification is in order. As you'd see when consulting the other very good answers here, arrays are most definitely not pointers. They do however decay into ones in enough contexts to warrant a decades long error in teaching about them (but I digress).
What I originally wrote refers to code as follows:
void func(int **p_buff)
{
}
//...
int a = 0, *pa = &a;
func(&pa);
//...
int a[3][10];
int *a_pts[3] = { a[0], a[1], a[2] };
func(a_pts);
//...
int **a = malloc(10 * sizeof *a);
for(int i = 0; i < 10; ++i)
a[i] = malloc(i * sizeof *a[i]);
func(a);
Assume func and each code snippet is compiled in a separate translation unit. Each example (barring any typos by me) is valid C. The arrays will decay into a "pointer-to-a-pointer" when passed as arguments. How is the definition of func to know what exactly it was passed from the type of its parameter alone!? The answer is that it cannot. The static type of p_buff is int**, but it still allows func to indirectly access (parts of) objects with vastly different effective types.
The declaration int **arr says: "declare arr as a pointer to a pointer to an integer". It (if valid) points to a single pointer that points (if valid) to a single integer object. As it is possible to use pointer arithmetic with either level of indirection (i.e. *arr is the same as arr[0] and **arr is the same as arr[0][0]) , the object can be used for accessing any of the 3 from your question (that is, for second, access an array of pointers to integers, and for third, access an array of pointers to first elements of integer arrays), provided that the pointers point to the first elements of the arrays...
Yet, arr is still declared as a pointer to a single pointer to a single integer object. It is also possible to declare a pointer to an array of defined dimensions. Here a is declared as a pointer to 10-element array of pointers to arrays of 10 integers:
cdecl> declare a as pointer to array 10 of pointer to array 10 of int;
int (*(*a)[10])[10]
In practice array pointers are most used for passing in multidimensional arrays of constant dimensions into functions, and for passing in variable-length arrays. The syntax to declare a variable as a pointer to an array is seldom seen, as whenever they're passed into a function, it is somewhat easier to use parameters of type "array of undefined size" instead, so instead of declaring
void func(int (*a)[10]);
one could use
void func(int a[][10])
to pass in a a multidimensional array of arrays of 10 integers. Alternatively, a typedef can be used to lessen the headache.
How can I know if :
arr is a pointer to a pointer of an integer
It is always a pointer to pointer to integer.
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
It can never be that. A pointer to an array of pointers to integers would be declared like this:
int* (*arr)[n]
It sounds as if you have been tricked to use int** by poor teachers/books/tutorials. It is almost always incorrect practice, as explained here and here and (
with detailed explanation about array pointers) here.
EDIT
Finally got around to writing a detailed post explaining what arrays are, what look-up tables are, why the latter are bad and what you should use instead: Correctly allocating multi-dimensional arrays.
Having solely the declaration of the variable, you cannot distinguish the three cases. One can still discuss if one should not use something like int *x[10] to express an array of 10 pointers to ints or something else; but int **x can - due to pointer arithmetics, be used in the three different ways, each way assuming a different memory layout with the (good) chance to make the wrong assumption.
Consider the following example, where an int ** is used in three different ways, i.e. p2p2i_v1 as a pointer to a pointer to a (single) int, p2p2i_v2 as a pointer to an array of pointers to int, and p2p2i_v3 as a pointer to a pointer to an array of ints. Note that you cannot distinguish these three meanings solely by the type, which is int** for all three. But with different initialisations, accessing each of them in the wrong way yields something unpredictable, except accessing the very first elements:
int i1=1,i2=2,i3=3,i4=4;
int *p2i = &i1;
int **p2p2i_v1 = &p2i; // pointer to a pointer to a single int
int *arrayOfp2i[4] = { &i1, &i2, &i3, &i4 };
int **p2p2i_v2 = arrayOfp2i; // pointer to an array of pointers to int
int arrayOfI[4] = { 5,6,7,8 };
int *p2arrayOfi = arrayOfI;
int **p2p2i_v3 = &p2arrayOfi; // pointer to a pointer to an array of ints
// assuming a pointer to a pointer to a single int:
int derefi1_v1 = *p2p2i_v1[0]; // correct; yields 1
int derefi1_v2 = *p2p2i_v2[0]; // correct; yields 1
int derefi1_v3 = *p2p2i_v3[0]; // correct; yields 5
// assuming a pointer to an array of pointers to int's
int derefi1_v1_at1 = *p2p2i_v1[1]; // incorrect, yields ? or seg fault
int derefi1_v2_at1 = *p2p2i_v2[1]; // correct; yields 2
int derefi1_v3_at1 = *p2p2i_v3[1]; // incorrect, yields ? or seg fault
// assuming a pointer to an array of pointers to an array of int's
int derefarray_at1_v1 = (*p2p2i_v1)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v2 = (*p2p2i_v2)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v3 = (*p2p2i_v3)[1]; // correct; yields 6;
How can I know if :
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
You cannot. It can be any of those. What it ends up being depends on how you allocate / use it.
So if you write code using these, document what you're doing with them, pass size parameters to the functions using them, and generally be sure about what you allocated before using it.
Pointers do not keep the information whether they point to a single object or an object that is an element of an array. Moreover for the pointer arithmetic single objects are considered like arrays consisting from one element.
Consider these declarations
int a;
int a1[1];
int a2[10];
int *p;
p = &a;
//...
p = a1;
//...
p = a2;
In this example the pointer p deals with addresses. It does not know whether the address it stores points to a single object like a or to the first element of the array a1 that has only one element or to the first element of the array a2 that has ten elements.
The type of
int ** arr;
only have one valid interpretation. It is:
arr is a pointer to a pointer to an integer
If you have no more information than the declaration above, that is all you can know about it, i.e. if arr is probably initialized, it points to another pointer, which - if probably initialized - points to an integer.
Assuming proper initialization, the only guaranteed valid way to use it is:
**arr = 42;
int a = **arr;
However, C allows you to use it in multiple ways.
• arr can be used as a pointer to a pointer to an integer (i.e. the basic case)
int a = **arr;
• arr can be used as a pointer to a pointer to an an array of integer
int a = (*arr)[4];
• arr can be used as a pointer to an array of pointers to integers
int a = *(arr[4]);
• arr can be used as a pointer to an array of pointers to arrays of integers
int a = arr[4][4];
In the last three cases it may look as if you have an array. However, the type is not an array. The type is always just a pointer to a pointer to an integer - the dereferencing is pointer arithmetic. It is nothing like a 2D array.
To know which is valid for the program at hand, you need to look at the code initializing arr.
Update
For the updated part of the question:
If you have:
void foo(char** x) { .... };
the only thing that you know for sure is that **x will give a char and *x will give you a char pointer (in both cases proper initialization of x is assumed).
If you want to use x in another way, e.g. x[2] to get the third char pointer, it requires that the caller has initialized x so that it points to a memory area that has at least 3 consecutive char pointers. This can be described as a contract for calling foo.
C syntax is logical. As an asterisk before the identifier in the declaration means pointer to the type of the variable, two asterisks mean pointer to a pointer to the type of the variable.
In this case arr is a pointer to a pointer to integer.
There are several usages of double pointers. For instance you could represent a matrix with a pointer to a vector of pointers. Each pointer in this vector points to the row of the matrix itself.
One can also create a two dimensional array using it,like this
int **arr=(int**)malloc(row*(sizeof(int*)));
for(i=0;i<row;i++) {
*(arr+i)=(int*)malloc(sizeof(int)*col); //You can use this also. Meaning of both is same. //
arr[i]=(int*)malloc(sizeof(int)*col); }
There is one trick when using pointers, read it from right hand side to the left hand side:
int** arr = NULL;
What do you get: arr, *, *, int, so array is a pointer to a pointer to an integer.
And int **arr; is the same as int** arr;.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.
There are already good answers here, but I want to mention my "goto" site for complicated declarations: http://cdecl.org/
Visit the site, paste your declaration and it will translate it to English.
For int ** arr;, it says declare arr as pointer to pointer to int.
The site also shows examples. Test yourself on them, then hover your cursor to see the answer.
(double (^)(int , long long ))foo
cast foo into block(int, long long) returning double
int (*(*foo)(void ))[3]
declare foo as pointer to function (void) returning pointer to array 3 of int
It will also translate English into C declarations, which is prety neat - if you get the description correct.
So this was presented in our class (I was absent that time):
typedef struct{
int *items;
int size;
int max;
}list;
and a list was passed to a function:
void append(list *l, int x){
if(l->size==l->max){
expand(l);
}
l->items[l->size++] = x;
}
My question is, how can an int pointer have an index? I thought indexes were used on arrays? Can that be done?
I'm new to C. So yeah.
A pointer can point at either 1 or n elements of its type. There is no way of telling which it is just from the declaration. We can assume that items is the address of the first element of an array. Since arrays store their elements in sequence, when you index the pointer, you really apply an offset from the first address. Hence, you index into the array that the pointer points at.
int values[5]; // Simple array.
int* p = values; // p points to the first element of the array values.
p[2] = 34; // Equivalent to values[2] = 34;
A pointer is simply the address to the memory space allocated for your object/array/int.
You can have a pointer to anything memory-related in C. You just say, here is my int, here is my array, etc...
How to turn an int pointer to an array
Strictly speaking: You cannot.
Any pointer can be treated as an array. An array is a sort of 2nd class citizen, and in most places the compiler treats an array as a pointer, and whenever an array is passed to a function, the compiler actually passes the address of the first element of the array. In fact, a[b] is considered to be *(a + b) (which can lead to some pretty incomprehensible code!)
So in your structure, items can be treated as a plain integer pointer, or the address of an array (as is done here).