-
Notifications
You must be signed in to change notification settings - Fork 0
section8_arrays
The concept of an array is pretty straightforward. So far, the only way you had for storing data in memory was with elementary variables. That is not flexible enough when you need to deal with larger sets of data. For example, you might be interested in storing the grades of students from a class and perform different tasks, for instance, compute the average grade for that particular class, finding the largest and maximum grades, and so on.
Imagine you create a single variable for storing each grade. If the class has 30 students, that's a huge amount of variables. Moreover, imagine having to build a statement for adding all grades!
Arrays really make this job easy.
An array is a collection of sequential objects in memory. Those objects have the same data type. You can access any element at any time in constant time (given the base address of the array and the index for the element you want, you can easily compute the address for the wanted element).
Declaring an array is similar to declaring a variable. You must specify a data type (all elements in the array must have the same data type), a name for the array and a size.
int arr[10];
The declaration above reserves enough space for storing 10 integer elements (each integer takes 4 bytes, thus 40 bytes in total).
In order to access an element in the array you must tell an index. We will see later how these indexes are used to access each element. For now, all you need to know is that the first element is index 0, the second element is index 1, ..., and the last element is the size of the array less 1 (because indexes start at 0).
int arr[10];
arr[0] = -5; /* first element */
arr[9] = 10; /* last element */
arr[10] = 9; /* ERROR: this element doesn't belong to the array, possible segmentation fault if you are lucky (sometimes is good to see things blowing, trust me */
The statements above are all assigning constant values on different array elements. In order to simply read an element, you access the same way:
int first_element = arr[0]; /* getting the fist value from the array */
At this stage you know to declare and initialize specific elements of the array. Let's assume that by the time you are declaring the array you want to initialize it with some values. You could manually assign the value for each position:
int arr[5];
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
/* ... */
Fortunatelly, there's a much more simple way:
int arr[5] = {0,1,2,3,4};
You can open brackets, {
and specify the values separated by comma in between and close the bracket, }
.
If you want to fill the whole array you can optionally omit the size in the declaration. The compiler automatically will assume the size is the number of elements you are assigning.
int arr[] = {0, 1, 2, 3, 4}; /* array of size 5 */
Finally, you can also declare the array with a size but only initialize some of the first elements. The remaining elements are initialize to zero.
int arr[5] = {0, 1}; /* 0 1 0 0 0 */
Before C99 it was not possible to use variables for defining the array size, you had to use constant values.
The following example either fails or displays an error and compiling for C89.
#include <stdio.h>
int main() {
int x;
/* ask user for size */
printf("Size ? ");
scanf("%d", &x);
/* declare array with specified size */
int arr[x] = {0};
/* display values */
int i;
for(i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
demo.c: In function ‘main’:
demo.c:7:2: warning: ISO C90 forbids variable length array ‘arr’ [-Wvla]
int arr[x];
^~~
demo.c:7:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
It's possible to know the size of an array when working directly with stack allocated arrays.
Definition: A stack is a region of memory reserved for the program where all automatic variables and function calls related data is stored. There's another region, called the heap, where all dynamically allocated memory is stored. We didn't covered dynamic memory yet, therefore all variables declared so far are automatic and stored in the stack.
In order to get the size you can use the sizeof
operator. It looks more like a function, due it's syntax, but it's just an operator. This operator evaluates to the full amount of memory taken by a variable. Let's say you have an array int a[10]
. When you apply the operator sizeof
it evaluaste to 40, because each integer value takes 4 bytes and the array has 10 elements. This is not enough to know how many elements the array has. However, you also know the type of elements. Therefore you can use an expression like sizeof(a)/sizeof(int)
which evaluates to 40/4
, which is 10
. Simple math. Total amount of memory used by the array divided by the each of element gives the number of elements in the array, whenever the array is initialized or not. Recall that arrays in C are static, they don't grow or shrink. That's only possible with dynamic memory.
What's important to remember is that this trick only works if you use the array variable. For instance, let's say that you create an array, int a[10]
and declare and instantiate a pointer for integers that references the array: int *ptr = a
. If you apply sizeof
in ptr
variable, you get 4 or 8, depending on the CPU architecture. In this case sizeof
is just telling you how many bytes a pointer variable takes.
This notion is important to understand some of the challenges with passing arrays to functions.
Soon...