Where it started
I've been procrastinating about learning DSA for a while now but finally I started the journey. I chose C as the language I want to learn with because of its low level nature which i think would enforce a deeper understanding.
what are arrays and why
In c, arrays are a collection of data of the same type. You could have an array of integers or an array of characters which is also known as a string.
Arrays are important in the sense that they help organize data and ease the process of manipulating data. Take for instance you wanted to store the marks for 10 students and compute the average eventually.
Option A: You could do it is you could have ten different integer variables for each student's marks then calculate the average for all of them.
Option B: Since all marks are of type integer you could store them in one variable (a marks array) and calculate the average from there. This is how you would do that.
int marks[10] = {10, 9, 3, 4, 7, 9, 6, 8, 2, 5}
Clearly option B is more organized, easy to manipulate and memory efficient in comparison to A.
So how do you declare an array?
It's good to understand the difference between declaration, definition and initialization when it comes to variables in c.
- Declaration: simply announcing a variables name to the compiler so it knows it exists.
- Definition: when memory for a defined variable is allocated.
- Initialization: when a value is assigned to a given variable.
Most of the time but not always declaration and definition occur at the same time together. For example we want to declare an array marks which will hold integers, so we say:
int marks but this is incomplete since we're defining an array and not a simple integer. So to complete the array declaration we also need to define its length, i.e.
int marks[10]
After defining our variable we can initialize it like we had done earlier before:
int marks[10] = {10, 9, 3, 4, 7, 9, 6, 8, 2, 5}
Another thing to note is once an array is declared in c its type cannot be changed. This is because C is a statically typed language. This means that the types of variables are declared explicitly and then checked during compilation(compile time) i.e. before the application runs.
Other language types include dynamically typed languages which means that variable types are checked during runtime. No explicit type checks are enforced when the developer is writing the code. A good example of this is JavaScript.
Lastly there are hybrids of both statically and dynamically typed languages. In essence this means that as a developer you have the option to assign types before run/compile time or the language will assign types for you dynamically during run/compile time.
Now that we have defined our array how can we access it..
Let's try access the items in the array and compute the average.
Pointers
This is where pointers come in. You can think of pointers as memory holders. They basically hold the memory address of a variable that has been declared. The size of a pointer is actually 8 bytes in a 64 bit machine and 4 bytes in a 32 bit machine, (the latter is less common nowadays). The type of the pointer during declaration should be similar to the type of the variable you want to point to. So if i declare an integer variable age whose value is 19, and an integer pointer p and assign it the address of age, p will always show us where age lives in memory and can help us access and use age in our computation. Size of pointers is consistent and does not change once declared.
int age = 19;
int *p;
// assigning the address of age to p
p = &age;
// we can change the value of age to 20 using our pointer
*p = 20; // this is called dereferencing
There's a lot to pointers which you can check out later but this is enough for now.
- The (*) operator is called a dereferencing operator and helps us access and manipulate the value of the variable that out pointer is pointing to.
- The (&) operator is called the address of operator and it helps us access the memory address of the variable that our pointer points to.
now back to the array
One thing to note about the nature of arrays in memory(RAM) is that they are stored in a contiguous nature, this means their memory addresses follow each other one after the other. If we have int arr[] = {10, 20, 15} and the memory address of 10 is 0x01 that would mean that the memory addresses of 20 & b15 would be 0x02 & 0x03 respectively.
Using pointers, if we declare a pointer that pointing to the array arr i.e. int p = &arr; dereferencing p will give us the value of the first item in the array, so, *p is going to be 10. To get the value of the second item in the array we need to do some pointer arithmetic, which basically is *(p + 1) and to get the third value we would do something like *(p + 2) you see the pattern.
Knowing all this, we can now calculate the average mark for 5 students. Check out the code below,
#include <stdio.h>
int main()
{
int marks[5] = {9, 11, 10, 14, 6};
int *marksPtr = marks;
int sum = 0;
int n = sizeof(marks) / sizeof(marks[0]);
int avg;
for (int i = 0; i < n; i++)
{
printf("We are currently at index %d and item is: %d \n", i, *(marksPtr + i));
sum += *(marksPtr + i);
// marksPtr++;
}
printf("Sum after looping: %d \n", sum);
// so to get the average we do sum/size
avg = sum / n;
printf("Average is: %d\n", avg);
return 0;
}
Please compile, run and experiment with the code to get a deeper understanding.
That said, this is just the start of my DSA journey in C and Python(in future). Next, I’ll be exploring pointer arithmetic and dynamic memory allocation — one step at a time. Share and follow for more.
Top comments (3)
You know that, for any pointer
p,*(p + i)is the same asp[i], right? Hence, you can write:Similarly, for any array
a,a[i]is the same as*(a + i), right? And since addition is commutative,*(i + a), and thereforei[a]. (Try it.)BTW, it's
p = a, notp = &a, since the name of an array in an expression "decays" into a pointer to its first element.Hey Paul, thanks for the feedback, this
i[a]is correct as well... just chose to write its as I did for simplicity/clarity/readability of whoever's following and is more conventional among developers.Also there's nothing inherently wrong with writing
p = &asince the address of the array is equal to the address of the first item of the array. Bothp = aandp = &amean the same thing in the context of the array, just that the latter is more explicit and is consistent to previous examples in the article.That's not true. If you do:
you'll get:
In C, "pointer to array" is a wholly separate thing. The type of
&ais "pointer to array 10 of int," i.e., the size is part of the type, and not "pointer to int":To access a value, you have to dereference the pointer first:
Note that they do point to the same address in memory, but the types are treated differently. Pointers-to-array don't occur often in practice because, even though the size is part of the type, it's part of the type statically (at compile time). There's no way to pass the pointer with its size dynamically (at run time) to a generic function that accepts any sized array and that function would know its size.