Joseph Haugh
University of New Mexico
What is the output of the following pieces of code?
void foo(int arr[], int n) {
int i, k, j;
for (i = 1; i < n; i++) {
k = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > k) {
arr[j + 1] = arr[j];
j = j - 1;
}
printf("arr[%d+1]=%d\n", j, k);
arr[j + 1] = k;
}
}
void main(void) {
int arr[] = {5, 2, 4, 6, 1, 3};
int n = 6;
foo(arr, n);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
arr[-1+1]=2
arr[0+1]=4
arr[2+1]=6
arr[-1+1]=1
arr[1+1]=3
1 2 3 4 5 6
void shaker(int arr[], int n) {
int swp = 1;
while (swp) {
swp = 0;
for (int i = 0; i < n - 1; i++) {
if (arr[i] > arr[i+1]) {
sw(arr, i, i+1);
swp = 1;
}}
if (!swp) break;
n--;
for (int i = n - 1; i > 0; i--) {
if (arr[i] > arr[i+1]) {
sw(arr, i, i+1);
swp = 1;
}}
}}
void sw(int arr[], int x, int y) {
printf("swing: x=%d, y=%d\n",
x, y);
int t = arr[x];
arr[x] = arr[y];
arr[y] = t;
}
void main(void) {
int arr[] = {5, 2, 4, 6, 1, 3};
int n = 6;
shaker(arr, n);
for (int i = 0; i < n; i++) {
printf("%d", arr[i]);
}
printf("\n");
}
swing: x=0, y=1
swing: x=1, y=2
swing: x=3, y=4
swing: x=4, y=5
swing: x=2, y=3
swing: x=1, y=2
swing: x=0, y=1
swing: x=3, y=4
swing: x=2, y=3
123456
void main(void) {
int x = 5;
int *y = &x;
*y + 3;
printf("x=%d\n", x);
}
void main(void) {
int x = 5;
int *y = &x;
*y + 3;
printf("x=%d\n", x);
}
x = 5
void main(void) {
int x = 5;
int y = *(&x) + 3;
printf("x=%d, y=%d\n", x, y);
}
void main(void) {
int x = 5;
int y = *(&x) + 3;
printf("x=%d, y=%d\n", x, y);
}
x = 5, y = 8
void main(void) {
/* Assume sizeof(int) = 4 */
int x = 5; /* addr = 0x40 */
int *y = &x + x;
printf("&x=%p, y=%p\n", &x, y);
}
void main(void) {
/* Assume sizeof(int) = 4 */
int x = 5; /* addr = 0x40 */
int *y = &x + x;
printf("&x=%p, y=%p\n", &x, y);
}
&x=0x40, y=0x54
Recall that the following code:
int x = 5;
int *ptr = &x;
ptr = ptr + 3;
Really means this:
int x = 5;
int *ptr = &x;
ptr = ptr + 3 * sizeof(int);
Pointer arithmetic depends on the type of the pointer.
For example given this code:
ptr = 100;
ptr = ptr + 3;
Type | Size | Result |
---|---|---|
char * | 1 | 103 |
short * | 2 | 106 |
int * | 4 | 112 |
int ** | 4 | 112 |
struct foo * | sizeof(struct foo) | 100 + 3 * sizeof(struct foo) |
Have you ever considered how arrays are implemented?
You have probably heard arrays described as a contiguous block of memory.
What does contiguous mean in this context?
There are no gaps in the memory.
With this in mind can you see how we could implement arrays using pointers?
Pointer arithmetic can be used to implement arrays:
int *arr;
arr = malloc(3 * sizeof(int));
*(arr) = 0
*(arr + 1) = 1;
*(arr + 2) = 2;
This fills the first three elements of the array with 0, 1, and 2.
int *arr;
arr = malloc(3 * sizeof(int));
*(arr) = 0
*(arr + 1) = 1;
*(arr + 2) = 2;
Address | Value |
---|---|
0x100 | |
0x104 | |
0x108 |
int *arr;
arr = malloc(3 * sizeof(int));
*(arr) = 0
*(arr + 1) = 1;
*(arr + 2) = 2;
Address | Value |
---|---|
0x100 | 0 |
0x104 | |
0x108 |
int *arr;
arr = malloc(3 * sizeof(int));
*(arr) = 0
*(arr + 1) = 1;
*(arr + 2) = 2;
Address | Value |
---|---|
0x100 | 0 |
0x104 | 1 |
0x108 |
int *arr;
arr = malloc(3 * sizeof(int));
*(arr) = 0
*(arr + 1) = 1;
*(arr + 2) = 2;
Address | Value |
---|---|
0x100 | 0 |
0x104 | 1 |
0x108 | 2 |
You have to be careful to allocate enough memory for the array.
If you execute this code:
int *arr;
arr = malloc(3 * sizeof(int));
*(arr + 3) = 3;
You will be writing to memory that you do not own!
The compiler will not catch this error for you!
What does arr[x]
really mean?
arr[x] = *(arr + x)
arr[x]
*(arr + x)
*(x + arr)
x[arr]
Try it! It works but shouldn’t be used in practice.
&array[1] /* address of the second element */
&array[0] /* address of the first element */
array /* address of the first element */
int *array[3] /* allocates an array of three int pointers */
Is int the same size as int *?
As with most things in C it depends
On a 64 bit machine (which most machines are these days) it is not!
Try this:
void main(void) {
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(int *));
}
Arrays can be passed as parameters and are passed by value but the value is the address of the first element
void foo(int bar[3]) {
bar[0] = 0;
bar[1] = 2;
}
void main(void) {
int array[3];
foo(array);
}
First element is now 0 and second element is 2.
You can also pass arrays of variable size by passing in the length of the array as a separate parameter
void foo(int bar[], int count) {
int i;
for (i = 0; i < count; i++)
bar[i] = i;
}
void main(void) {
int array[3];
}
Remember that passing an array is the same as passing a pointer:
void foo(int *bar, int count) {
int i;
for (i = 0; i < count; i++)
bar[i] = i;
}
int main(void) {
int array[3];
foo(array, 3);
return 0;
}