Published on

Pointers in C

Authors
  • avatar
    Name
    Jyotir Sai
    Twitter
    Engineering Student

When I first started learning C in my University programming class, printf and scanf were some of the first functions I learned about. The printf function allowed me to take a phrase, variable or a combination of both and print it to the screen.

int main(void) {

    int age = 1;

    printf("I am %d years old", age);

    return 0;
}
I am 1 years old

In a similar fashion, I could retrieve user input and store it in a variable using scanf.

int main(void) {

    int age;

    printf("Enter age: ");
    scanf("%d", &age);

    printf("You are %d years old", age);

    return 0;
}
Enter Age: 1
You are 1 years old

The difference in using printf and scanf, was the '&' symbol before the variable name when passing it to the scanf function. The '&' symbol before a variable refers to retrieving the memory address of that variable. The scanf function takes the user input and stores it at the memory location of the variable thus, changing the value of the variable. In C, when a variable is passed to a function, the function operates on a copy of this variable. Therefore, changes made to this variable are not "seen" outside this function. Pointers allow an efficient way to solve this problem.

A pointer is a variable which has a memory address as its value. It can be used to 'point' to a memory address and retrieve or change the value stored at that memory address.

int main(void) {

    int age = 1;

    int *p1; // declaring a pointer
    p1 = &age; // assigning p1 to the address of the age variable

    printf("%d", *p1);

    return 0;
}
1

The * is the indirection operator which is used to declare pointers and retrieve values stored at a memory address. When we want to point to a memory address of a variable, we can assign the address of that variable to our pointer by placing an ampersand in front of the variable.

The pointer can be used to change the value of the variable it is pointing to.

int main(void) {

    int age = 1;

    int *p1; // declaring a pointer
    p1 = &age; // assigning p1 to the address of the age variable

    *p1 = 3; // changing value stored at memory address to 3

    printf("%d", age); // printing the original age variable

    return 0;
}
3

Pointers can also be used with arrays.

int main(void) {

    int ages[5] = {1, 10, 20, 30, 40}; // initializing array

    int *p1; // declaring a pointer
    p1 = ages; // assigning p1 to the address of the first element in the age array

    *p1 = 9; // changing first element in array to 9

    printf("%d", ages[0]); // printing the original age variable

    return 0;
}
9

An important note with arrays is that the name of the array (ex. ages) is also equal to the address of the first element in the array. In other words "ages" is the same as "&ages[0]". Therefore, it is common to not see any ampersands when using a pointer with arrays.

If we want our pointer to change the value stored at the 3rd element in our ages array we can do the following:

int main(void) {

    int ages[5] = {1, 10, 20, 30, 40}; // initializing array

    int *p1; // declaring a pointer
    p1 = ages+2; // assigning p1 to the address of the age 3rd element in the age array

    *p1 = 9; // changing third element in array to 9

    printf("%d", ages[2]); // printing the original age variable

    return 0;
}
9

The p1 = ages+2 code tells the pointer to move over 2 memory blocks from ages[0] which gives you ages[2]. Since an int is usually 4 bytes, this code actually tells the pointer to move over by 8 bytes (2 memory blocks).

The following code sample shows how we can retrieve the value stored at ages[3] which is 30.

int main(void) {

    int ages[5] = {1, 10, 20, 30, 40}; // initializing array

    int *p1; // declaring a pointer
    int fourth;

    p1 = ages; // assigning p1 to the address of the age 4th element in the age array

    fourth = *(p1+3); // starting from p1[0], move over 3 memory blocks

    printf("%d", fourth); // printing the original age variable

    return 0;
}
30

The following are equivalent:

ages+1 == &ages[1]; // same memory address
*(ages+1) == ages[1]; // same value

To summarize, why does scanf require the address of a variable? When a user enters a value, scanf takes that value and assigns it to the variable you pass to it. In other words, it is changing whatever is stored originally in the variable to whatever the user has input. Since functions in C make copies of the variable, the value that the user entered would simply be stored in a copy of the original variable, not the actual variable itself. Therefore, passing a pointer allows the function to actually change the value stored at the memory address of the original variable.