C struct pointer accessing fields - c

I've read that if we have a pointer to a struct type object we can't access the object field by using the asterisk (*) but we need to use this -> (like an arrow sign).
Now although I read about it I didn't understand why we can't use the asterisk, I'll try to provide a code example and a picture of how I visualize a struct in memory to help you understand what is preventing me from understanding this topic.
Okay, so here's our code :
#include <stdio.h>
typedef struct MyStruct
{
char c1;
char c2;
} MyStruct;
int main()
{
MyStruct s1; // Let's assume s1's address is 0x34A
s1.c1 = 'A';
s1.c2 = 'B';
printf("s1 c1 is %c and c2 is %c.\n", s1.c1, s1.c2);
MyStruct *p = &s1; // Declaring our pointer to point to s1 address, so p points to 0x34A
printf("s1 c1 is %c and c2 is %c.\n", p->c1, p->c2); // I know this is the valid way
printf("s1 c1 is %c.\n", *p.c1); // I don't understand why this would be invalid
return 0;
}
Now let me try to explain why I don't understand why this syntax is invalid.
So p is pointing to the address of s1 which is 0x34A and as I see it this is how I see s1 in memory:
So what I imagine it as in memory is that s1 has it's own address of course which in our example is 0x34A and it points to c1 address in memory which is followed up by c2 address.
So when I do this :
printf("s1 c1 is %c.\n", (*p.c1)++, *p.c2);
I think of it as I'm accessing the value that is inside the pointer address by our pointer so we're accessing the value which is c1.
But as I said it's invalid and I just breaking my head trying to understand why, I've tried to read about it but couldn't really put the finger on the answer that will satisfy me on why really, so I've provided the code example and the picture so you could get into my head and try and see why I'm thinking wrong here.

*p.c1 is parsed as *(p.c1) not (*p).c1.
So when you do *(p.c1), you attempt to use the dot operator on a pointer, which fails.

There is a precedence problem over here. If you want to access like this then go for (*p).c1.
Now by doing (*p), you will reach to your structure and then after members.

Related

array arithmetic - pointer types indexing

In my previous question:
Pointer dereference array index I have asked about struct being dereferenced. (I will paste a snippet of code from there for recap):
#include <stdio.h>
#include <stdlib.h>
struct Test { char c; } foo;
int main (void) {
struct Test **ar;
ar=malloc(16);
*ar=malloc(0); //prerequisite for second case (without getting some address from OS, I cannot go 'through' *ar to (*ar+1).
//Does not matter allocation of zero bytes. (only to get some valid address)
*(ar+1) = &foo;
//(**(ar+1)).c='c'; //// first case - works
(*(*ar+1)).c='c'; //// second case - also works, with prerequisite
printf("%c\n", (*(*ar+1)).c); //prints 'c'
return 0;
}
I still do understand between pointer adding +1 in first vs second case. Well I do in the second - adding sizeof(struct Test*) to the address *ar, which like array indexing (so *ar is name pointer of array). But in the first case? what does (**(ar+1)) do? How can I add (what?) some kind of pointer type sizeof(struct Test**) when ar is not array? *(ar+1) dereference address that does not belong to me, but (*ar+1) dereference address of pointer (sizeof(struct Test*)) that DOES belong to me (an array member). So why does the first case work? (from the link, I am trying to give my understanding by resolving type being indexed [ e.g. - in first case a "step/index" is made by sizeof(struct Test**) and in second case by sizeof(struct Test*), but both have same size) - just take a look at the link.
So why does the first case work?
(**(ar+1)).c='c' doesn't work at all on my specific system.
(**(ar+1)) performs pointer arithmetic on a struct Test ** type, and (*(*ar+1)) performs pointer arithmetic on a struct Test* type.
This means that in the former case, arithmetic is done by sizeof(struct Test *) bytes, in the latter case on sizeof(struct Test) bytes.
The compiler might add padding inside your struct so that it ends up as 4 bytes etc, whatever size a pointer happens to be on your system. So they might end up at the same address by luck. Pointer sizes are commonly 2, 4 or 8 bytes, depending on if a 16, 32 or 64 bit address bus is used.
It is not very meaningful to ponder about what obscure code like this does. Explicit pointer arithmetic in general should be avoided, it is much better practice to use the [] operator to get readable code.
Also please note that malloc(0) gives "either a null pointer
is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object." If you get a null pointer and then attempt arithmetic, you have undefined behavior and anything might happen.
So let's break up your code:
Declaring a pointer to pointer to struct Test.
struct Test **ar;
Allocating space for pointers, if your system is 64 bits you are allocating space for exactly 2 contiguous pointers.
ar = malloc(16);
Allocating memory block and assigning it to the first pointer (arr[0] = malloc(0)), this is never used, but without compiler optimization you still need to initialize it, allocating 0 bytes might not be the best option since it invokes undefined behaviour but since you never store anything there it doesn't cause problems.
*ar = malloc(0);
You are storing foo address in pointer number 2, which, since it works, leads me to believe that your system is indeed 64 bits.
*(ar+1) = &foo;
Works, assigning 'c' to char c to one past the foo struct. The same as ar[0][1].c ='c';
(*(*ar+1)).c = 'c';
printf("%c\n", (*(*ar+1)).c); //prints 'c'
The out of bounds accesses work because in C one past the end of an array or allocated memory block is available, and it looks like your implementation let's you access it to write and dereference, though it's out of bounds, mine too by the way, this is not always true so you can't expect it to always work.
This all works by chance (or maybe not), because you allocate the needed space for the 2 pointers.
Now lets make some changes to you allocation to compare with what you have, and let's mess around with the structure's paddings to store and access values out of the bounds of the allocated memory.
#include <stdio.h>
#include <stdlib.h>
struct Test
{
char c;
} foo;
int main(void)
{
struct Test **ar; //declaring a pointer to pointer to struct Test
ar = malloc(sizeof(*ar) * 2); //allocation of space for 2 pointers to struct Test.
//without optimization you still need to allocate space
//or otherwise initialize the 1st pointer to avoid UB
*(ar + 0) = malloc(sizeof(**ar)); //or ar[0] = ... or *ar = ...
*(ar + 1) = &foo; //or ar[1] = ... storing foo's address in the second pointer
(*(*ar + 1)).c = 'c'; //works fine, one past the allocated memory
printf("%c\n", ar[0][1].c);
(**(ar + 1)).c = 'b'; //works, actually foo
printf("%c\n", ar[1][0].c);
(*(*(ar + 1) + 1)).c = 'a'; //also works, accessing ou of bounds
printf("%c\n", ar[1][1].c);
printf("%c\n", foo.c); //test print foo
return 0;
}
Live demo
This is much better not only in terms of readability but also in terms of portability since is the systems who decides what's the size of the pointers.
Now look at this simplified code:
#include <stdio.h>
#include <stdlib.h>
struct Test
{
char c;
} foo;
int main(void)
{
struct Test** ar;
ar = malloc(sizeof(*ar) * 2);
ar[0] = malloc(sizeof(**ar)); //or *ar = ...
ar[1] = &foo; //or *(ar + 1) = ...
ar[0]->c = 'a';
printf("%c\n", ar[0]->c);
ar[1]->c = 'c';
printf("%c\n", ar[1]->c);
printf("%c\n", foo.c); //ok foo has 'c'
return 0;
}
Look how easy it is to use double pointers if one doesn't overcomplicate things.

Access with a pointer on two structures with an array

I got another issue with my Code. I want to access on all 3 values with a simple pointer usage. But my Pointer jumps too far.
My Output is this:
Value is 1
Value is 4194432
Value is 2686824
I guess that my Problem is, that my pointer is from the wrong type. So pointer++ dont jump to the next array element. I really dont know, how i can solve this.
(It's only a simple example to reproduce my problem, so dont look for sense in doing this)
typedef struct _A {
int value;
}A;
typedef struct _B {
A array[10];
}B;
int main()
{
A atest;
B btest;
B *p=NULL;
btest.array[0].value=1;
btest.array[1].value=3;
btest.array[2].value=5;
p=malloc(10 * sizeof(btest));
p=&btest.array;
int i=0;
for(i=0;i<3;i++)
{
printf("\n%d. Value is %d\n",i+1,p++->array->value);
}
return 0;
}
Thx for reading and if something is missing in my explanation, then i will apologize and add it.
EDIT:
Additionally to Some Programmers Dude Sollution, i add a simple cast mechanic:
q=(A*) p;
q++;
p =(B*)q;
Thx for your help :)
These lines
p=malloc(10 * sizeof(btest));
p=&btest.array;
contains two problems. The first is that with the second assignment you lose the memory you allocated. It does not copy the contents of btest.array.
The second problem is that p is a pointer to B but &btest.array is a pointer to an array of ten A elements (its type is A (*)[10]). Those two are very different types.
If you want to copy btest into the memory allocated for p (which is a pointer to ten B structures which is a little overkill) do e.g.
p=malloc(sizeof *p);
memcpy(p, &btest, sizeof *p);
Then to the next problem:
p++->array->value
The p++ will make p point to the next element in the array pointed to by p, but that's wrong. You should loop over p->array instead like
p->array[i].value

Assignment of structures with pointers in C

Can anyone explain the output of the following piece of code:
int main() {
struct student {
char *nume;
char an[5];
} a, b;
a.nume = (char*)malloc(20);
strcpy(a.nume, "Alex Popescu");
strcpy(a.an, "1996");
printf("%s %s\n", a.nume, a.an);
b = a;
strcpy(b.nume, "Emil Ionescu");
strcpy(b.an, "1997");
printf("%s %s\n", b.nume, b.an);
struct student *pa = &a;
printf("%s %s\n", pa->nume, (*pa).an);
free(a.nume);
return 0;
}
The output is:
Alex Popescu 1996
Emil Ionescu 1997
Emil Ionescu 1996
What does b = a; do? Is b pointing to the same address as a? And when you change b.name to Emil Ionescu, a is changeing it's value too?
Why is only the name changed but the year remains 1996?
It does a 'shallow' copy of the struct.
Every member in a is copied to every member in b. Since a pointer points to some memory, in this case both pointers of both structs will point to the same memory. If that memory is changed, then both pointers will see that change.
But the array contains it's own memory, so the change of the array in one struct, will only affect that struct.
I think you are confused because you used a struct. There is nothing special about it, it just happens to hold a pointer and an array. You code would be the same if instead of two structs you used two pointers and two arrays and copied them manually. You should try that.

Unexpected C struct pointer size behaviour

I have some odd behaviour going on in my code which seems to be resulting from the use of a generic pointer though really I am totally uncertain. I have a fairly standard struct which looks like the following:
typedef struct {
char* name;
PyAutoCFunc ac_func;
void (*func)();
PyAutoType type_id;
int num_args;
PyAutoType arg_types[MAX_ARG_NUM];
} func_entry;
static func_entry* func_entries;
I am storing a static pointer to an array of these struct elements which is allocated on the heap. At the point where I create a new element of this array and insert it, its values look like this...
func_entry new_fe;
new_fe.name = malloc(strlen(name) + 1);
strcpy(new_fe.name, name);
... // Init rest of struct
func_entries[num_func_entries] = new_fe;
num_func_entries++;
func_entry* fe = &func_entries[num_func_entries-1];
printf("Setting function '%s' at address '%p', name address '%p'\n", name, fe, fe->name);
This outputs.
>>> Setting function 'graphics_viewport_set_title' at address '0xfe2d40', name address '0xe40fe0'
Notice the size and value of fe->name. I then store this pointer into a hashtable to retrieve later. In the hashtable this is stored as a simple void*. Later when I retrieve the pointer from the hashtable an odd thing happens.
func_entry* fe = PyAutoHashtable_Get(func_table, c_func_name);
printf("Getting function '%s' at address '%p', name address '%p'\n", c_func_name, fe, fe->name);
Which outputs.
>>> Getting function 'graphics_viewport_set_title' at address '0xfe2d40', name address '0x6e6f74656c656b73'
The address of fe has clearly been in and out of the hashtable without issue, but the size and address of fe->name has changed. Even more weirdly is that fe->name is a different size to what it was before and even a different size to fe. Trying to access fe->name gives me a segfault and I am unsure how to proceed.
Out of interest this seems to occur when I use the code in an application with several linked libraries, I'm fairly sure all the code I'm running is 64 bit.
I have run the above code successfully in a separate application and get a correct pointer for fe->name (a smaller one).
I am also running on Ubuntu Linux 64 bit and compiling with gcc.
This is really where my C ignorance shines though as I imagine it could be a million things. Can anyone shine some light?
That address for name looks like the result of memory corruption. It's completely unaligned, which is unlikely for an address returned by strdup off the heap.
It looks like you're out of scope for the structure you created. You mentioned it's created on the heap, but in the code it looks like it's probably created on the stack. This isn't all being done in the same function, is it? Is the code in the first block in a function that's existed before running the code in the later block? As soon as you exit that function the memory for that structure ceased to be, even though you retained a pointer to it. Later, when you pulled the pointer out of the hash table the memory had been overwritten and didn't have the pointer to name there anymore. If you're going to pass around pointers to structures allocate them dynamically by using malloc. They're exist until you explicitly get rid of them using free, instead of when the function ends.
Pointers always are of the same size whether its a pointer to a struct or a generic pointer (char * in olden days, void * in ANSI standard.)
Here's a simple example I whipped out so that you could understand structures, pointers (not in detail though but you get the idea.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person {
char *name;
int age;
};
void print(void *);
int main()
{
struct person *david;
if ((david = (struct person *)malloc(sizeof(struct person))) != NULL) {
david->name = strdup("David");
david->age = 40;
printf("sizeof david = %d, sizeof person = %d\n", sizeof david,
sizeof(struct person));
print((void *)david);
}
}
void print(void *p)
{
struct person *pp = (struct person *)p;
printf("sizeof p = %d, sizeof pp = %d\n%s %d\n", sizeof p, sizeof pp,
pp->name, pp->age);
}
Output
sizeof david = 8, sizeof person = 16
sizeof p = 8, sizeof pp = 8
David 40
Hope that helps.
It certainly looks as if something is writing over that data structure. The pointer value 0x6e6f74656c656b73 which you are seeing looks very suspicious indeed - it is ASCII for "noteleks", which is "skeleton" backwards. Perhaps this might give you an idea of what is overwriting your data.

How do pointer-to-pointers work in C? (and when might you use them?)

How do pointers-to-pointers work in C?
When might you use them?
Let's assume an 8 bit computer with 8 bit addresses (and thus only 256 bytes of memory). This is part of that memory (the numbers at the top are the addresses):
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| | 58 | | | 63 | | 55 | | | h | e | l | l | o | \0 | |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
What you can see here, is that at address 63 the string "hello" starts. So in this case, if this is the only occurrence of "hello" in memory then,
const char *c = "hello";
... defines c to be a pointer to the (read-only) string "hello", and thus contains the value 63. c must itself be stored somewhere: in the example above at location 58. Of course we can not only point to characters, but also to other pointers. E.g.:
const char **cp = &c;
Now cp points to c, that is, it contains the address of c (which is 58). We can go even further. Consider:
const char ***cpp = &cp;
Now cpp stores the address of cp. So it has value 55 (based on the example above), and you guessed it: it is itself stored at address 60.
As to why one uses pointers to pointers:
The name of an array usually yields the address of its first element. So if the array contains elements of type t, a reference to the array has type t *. Now consider an array of arrays of type t: naturally a reference to this 2D array will have type (t *)* = t **, and is hence a pointer to a pointer.
Even though an array of strings sounds one-dimensional, it is in fact two-dimensional, since strings are character arrays. Hence: char **.
A function f will need to accept an argument of type t ** if it is to alter a variable of type t *.
Many other reasons that are too numerous to list here.
How do pointers to pointers work in C?
First a pointer is a variable, like any other variable, but that holds the address of a variable.
A pointer to a pointer is a variable, like any other variable, but that holds the address of a variable. That variable just happens to be a pointer.
When would you use them?
You can use them when you need to return a pointer to some memory on the heap, but not using the return value.
Example:
int getValueOf5(int *p)
{
*p = 5;
return 1;//success
}
int get1024HeapMemory(int **p)
{
*p = malloc(1024);
if(*p == 0)
return -1;//error
else
return 0;//success
}
And you call it like this:
int x;
getValueOf5(&x);//I want to fill the int varaible, so I pass it's address in
//At this point x holds 5
int *p;
get1024HeapMemory(&p);//I want to fill the int* variable, so I pass it's address in
//At this point p holds a memory address where 1024 bytes of memory is allocated on the heap
There are other uses too, like the main() argument of every C program has a pointer to a pointer for argv, where each element holds an array of chars that are the command line options. You must be careful though when you use pointers of pointers to point to 2 dimensional arrays, it's better to use a pointer to a 2 dimensional array instead.
Why it's dangerous?
void test()
{
double **a;
int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*)
double matrix[ROWS][COLUMNS];
int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double)
}
Here is an example of a pointer to a 2 dimensional array done properly:
int (*myPointerTo2DimArray)[ROWS][COLUMNS]
You can't use a pointer to a 2 dimensional array though if you want to support a variable number of elements for the ROWS and COLUMNS. But when you know before hand you would use a 2 dimensional array.
I like this "real world" code example of pointer to pointer usage, in Git 2.0, commit 7b1004b:
Linus once said:
I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc.
For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like:
if (prev)
prev->next = entry->next;
else
list_head = entry->next;
and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a
*pp = entry->next
Applying that simplification lets us lose 7 lines from this function even while adding 2 lines of comment.
- struct combine_diff_path *p, *pprev, *ptmp;
+ struct combine_diff_path *p, **tail = &curr;
Chris points out in the comments to the 2016 video "Linus Torvalds's Double Pointer Problem".
kumar points out in the comments the blog post "Linus on Understanding Pointers", where Grisha Trubetskoy explains:
Imagine you have a linked list defined as:
typedef struct list_entry {
int val;
struct list_entry *next;
} list_entry;
You need to iterate over it from the beginning to end and remove a specific element whose value equals the value of to_remove.
The more obvious way to do this would be:
list_entry *entry = head; /* assuming head exists and is the first entry of the list */
list_entry *prev = NULL;
while (entry) { /* line 4 */
if (entry->val == to_remove) /* this is the one to remove ; line 5 */
if (prev)
prev->next = entry->next; /* remove the entry ; line 7 */
else
head = entry->next; /* special case - first entry ; line 9 */
/* move on to the next entry */
prev = entry;
entry = entry->next;
}
What we are doing above is:
iterating over the list until entry is NULL, which means we’ve reached the end of the list (line 4).
When we come across an entry we want removed (line 5),
we assign the value of current next pointer to the previous one,
thus eliminating the current element (line 7).
There is a special case above - at the beginning of the iteration there is no previous entry (prev is NULL), and so to remove the first entry in the list you have to modify head itself (line 9).
What Linus was saying is that the above code could be simplified by making the previous element a pointer to a pointer rather than just a pointer.
The code then looks like this:
list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;
while (entry) {
if (entry->val == to_remove)
*pp = entry->next;
else
pp = &entry->next;
entry = entry->next;
}
The above code is very similar to the previous variant, but notice how we no longer need to watch for the special case of the first element of the list, since pp is not NULL at the beginning. Simple and clever.
Also, someone in that thread commented that the reason this is better is because *pp = entry->next is atomic. It is most certainly NOT atomic.
The above expression contains two dereference operators (* and ->) and one assignment, and neither of those three things is atomic.
This is a common misconception, but alas pretty much nothing in C should ever be assumed to be atomic (including the ++ and -- operators)!
When covering pointers on a programming course at university, we were given two hints as to how to begin learning about them. The first was to view Pointer Fun With Binky. The second was to think about the Haddocks' Eyes passage from Lewis Carroll's Through the Looking-Glass
“You are sad,” the Knight said in an anxious tone: “Let me sing you a song to comfort you.”
“Is it very long?” Alice asked, for she had heard a good deal of poetry that day.
“It's long,” said the Knight, “but it's very, very beautiful. Everybody that hears me sing it - either it brings the tears to their eyes, or else -”
“Or else what?” said Alice, for the Knight had made a sudden pause.
“Or else it doesn't, you know. The name of the song is called ‘Haddocks' Eyes.’”
“Oh, that's the name of the song, is it?" Alice said, trying to feel interested.
“No, you don't understand,” the Knight said, looking a little vexed. “That's what the name is called. The name really is ‘The Aged Aged Man.’”
“Then I ought to have said ‘That's what the song is called’?” Alice corrected herself.
“No, you oughtn't: that's quite another thing! The song is called ‘Ways And Means’: but that's only what it's called, you know!”
“Well, what is the song, then?” said Alice, who was by this time completely bewildered.
“I was coming to that,” the Knight said. “The song really is ‘A-sitting On A Gate’: and the tune's my own invention.”
Pointers to Pointers
Since we can have pointers to int, and pointers to char, and pointers to any structures we've defined, and in fact pointers to any type in C, it shouldn't come as too much of a surprise that we can have pointers to other pointers.
Consider the below figure and program to understand this concept better.
As per the figure, ptr1 is a single pointer which is having address of variable num.
ptr1 = &num;
Similarly ptr2 is a pointer to pointer(double pointer) which is having the address of pointer ptr1.
ptr2 = &ptr1;
A pointer which points to another pointer is known as double pointer. In this example ptr2 is a double pointer.
Values from above diagram :
Address of variable num has : 1000
Address of Pointer ptr1 is: 2000
Address of Pointer ptr2 is: 3000
Example:
#include <stdio.h>
int main ()
{
int num = 10;
int *ptr1;
int **ptr2;
// Take the address of var
ptr1 = &num;
// Take the address of ptr1 using address of operator &
ptr2 = &ptr1;
// Print the value
printf("Value of num = %d\n", num );
printf("Value available at *ptr1 = %d\n", *ptr1 );
printf("Value available at **ptr2 = %d\n", **ptr2);
}
Output:
Value of num = 10
Value available at *ptr1 = 10
Value available at **ptr2 = 10
A pointer-to-a-pointer is used when a reference to a pointer is required. For example, when you wish to modify the value (address pointed to) of a pointer variable declared in a calling function's scope inside a called function.
If you pass a single pointer in as an argument, you will be modifying local copies of the pointer, not the original pointer in the calling scope. With a pointer to a pointer, you modify the latter.
A pointer to a pointer is also called a handle. One usage for it is often when an object can be moved in memory or removed. One is often responsible to lock and unlock the usage of the object so it will not be moved when accessing it.
It's often used in memory restricted environment, ie the Palm OS.
computer.howstuffworks.com Link>>
www.flippinbits.com Link>>
it's a pointer to the pointer's address value. (that's terrible I know)
basically, it lets you pass a pointer to the value of the address of another pointer, so you can modify where another pointer is pointing from a sub function, like:
void changeptr(int** pp)
{
*pp=&someval;
}
You have a variable that contains an address of something. That's a pointer.
Then you have another variable that contains the address of the first variable. That's a pointer to pointer.
A pointer to pointer is, well, a pointer to pointer.
A meaningfull example of someType** is a bidimensional array: you have one array, filled with pointers to other arrays, so when you write
dpointer[5][6]
you access at the array that contains pointers to other arrays in his 5th position, get the pointer (let fpointer his name) and then access the 6th element of the array referenced to that array (so, fpointer[6]).
How it works:
It is a variable that can store another pointer.
When would you use them :
Many uses one of them is if your function wants to construct an array and return it to the caller.
//returns the array of roll nos {11, 12} through paramater
// return value is total number of students
int fun( int **i )
{
int *j;
*i = (int*)malloc ( 2*sizeof(int) );
**i = 11; // e.g., newly allocated memory 0x2000 store 11
j = *i;
j++;
*j = 12; ; // e.g., newly allocated memory 0x2004 store 12
return 2;
}
int main()
{
int *i;
int n = fun( &i ); // hey I don't know how many students are in your class please send all of their roll numbers.
for ( int j=0; j<n; j++ )
printf( "roll no = %d \n", i[j] );
return 0;
}
A 5-minute video explaining how pointers work:
There so many of the useful explanations, but I didnt found just a short description, so..
Basically pointer is address of the variable.
Short summary code:
int a, *p_a;//declaration of normal variable and int pointer variable
a = 56; //simply assign value
p_a = &a; //save address of "a" to pointer variable
*p_a = 15; //override the value of the variable
//print 0xfoo and 15
//- first is address, 2nd is value stored at this address (that is called dereference)
printf("pointer p_a is having value %d and targeting at variable value %d", p_a, *p_a);
Also useful info can be found in topic What means reference and dereference
And I am not so sure, when can be pointers useful, but in common it is necessary to use them when you are doing some manual/dynamic memory allocation- malloc, calloc, etc.
So I hope it will also helps for clarify the problematic :)

Resources