My solution uses strcpy(). The whole program, which calls atos() on argv is in q0.c:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *atos(char **a)
{
int i, size;
char *rv;
size = 1;
for (i = 0; a[i] != NULL; i++) size += (strlen(a[i])+1);
rv = (char *) malloc(sizeof(char)*size);
size = 0;
rv[0] = '\0';
for (i = 0; a[i] != NULL; i++) {
if (i != 0) {
rv[size] = ' ';
size++;
}
strcpy(rv+size, a[i]);
size += strlen(a[i]);
}
return rv;
}
main(int argc, char **argv)
{
char *s;
s = atos(argv);
printf("%s\n", s);
}
|
![]() |
![]() |
![]() |
![]() |
for (i = 0; i < 5; i++) printf("%12d ", b[i]);
printf("\n");
printf("\n");
|
Since b's value is 0xbfffdb48, b[0] is the value at that address: -1073851180. b[1] is the value four bytes after that address, and so on. The output is:
-1073751180 -1073751176 1611 7683 42335Now, look at the next two lines:
for (i = 0; i < 5; i++) printf("%s\n", c[i]);
printf("\n");
|
c's value is 0xbfffdb3c, so c[0] is 0xbfffdb60. Since we are printing c[0] as a string, we print the characters starting at 0xbfffdb60 and ending with the null character: "d|". Similarly, c[1] is 0xbfffdb68: "Binky". The output is:
d| Binky Luigi FredDontonio DontonioNow the next 7 lines:
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
printf("%12d ", a[i][j]);
}
printf("\n");
}
printf("\n");
|
a[0] is the value at 0xbfffdb30: 0xbfffdb4c. Since a is an (int **), we treat that as a pointer: a[0][0] is the integer at 0xbfffdb4c: -1073751176, and a[0][1] is the integer four bytes later: 1611. a[0][2] is the integer four bytes after that: 7683.
a[1] is the value four bytes after 0xbfffdb30, which is at 0xbfffdb34. Its value is 0xbfffdb54. Thus, a[1][0] is the integer at 0xbfffdb54: 7683, and a[1][1] is four bytes later: 42335.
The output is:
-1073751176 1611 7683
7683 42335 60605
31844 40554 1802398018
Now look at the next four lines:
for (b = a[0]; b < (int *) a[0][0]; b += 2) {
printf("%12d\n", *b);
}
printf("\n");
|
This loop sets b to 0xbfffdb4c, and increments it by 8 bytes (pointer arithmetic) on each iteration. Since a[0][0] equals 0xbfffdb78, this will iterate quite a few times:
| b | *b |
| 0xbfffdb4c | -1073751176 |
| 0xbfffdb54 | 7683 |
| 0xbfffdb5c | 60605 |
| 0xbfffdb64 | 40554 |
| 0xbfffdb6c | 1967915129 |
| 0xbfffdb74 | 1684369990 |
The final part of the code sets s to 0xbfffdb60 and t to 0xbfffdb61. At each iteration it sets s[0] to *t, and then increments t by seven:
| t | *t |
| 0xbfffdb61 | '|' |
| 0xbfffdb68 | 'B' |
| 0xbfffdb6f | 'u' |
| 0xbfffdb76 | 'e' |
| 0xbfffdb7d | 'n' |
| 0xbfffdb84 | 'z' |
Thus, s[0] is "|Buenz". The final word is the hex value at 0xbfffdb60. This is a little tricky. You can see that the hex value of four bytes is the hex value of the characters in reverse order. For example 31844 is equal 0x00007c64, which is equal to 'd', '|', '\0' and '\0'. Thus, 'd' is 0x64 and '|' is 0x7c. This means that *b is equal to '|' (0x7c), 'B' (0x42), 'u' (0x75) and 'e' (0x65) in reverse order: 0x6575427c.
The entire output is:
a: 0xbfffdb30
b: 0xbfffdb48
c: 0xbfffdb3c
-1073751180 -1073751176 1611 7683 42335
d|
Binky
Luigi
FredDontonio
Dontonio
-1073751176 1611 7683
7683 42335 60605
31844 40554 1802398018
-1073751176
7683
60605
40554
1967915129
1684369990
|Buenz 0x6575427c
|
To write this problem, I wrote a program that set up the stack, and then called messy_proc(), which printed the stack and then ran as on the test. If you run it on a lab machine, the output will be different, but it will be the same relative to a, b, and c. The program is in q3.c.
![]() |
Once this is done, parts A and B are straightforward:
Part A:
Part B:
Part C: sbrk(0) returns the first byte after the heap: 0x1c3b0.
Part D: Memory is paged -- therefore, the void really doesn't start until 0x1d000 (4K pages), or at the very least 0x1c400 (1K pages). Since 0x1c3c4 is before both of those addresses, it will complete successfully with no segmentation violation.
![]() |