代码1: 函数gets()的实现:
char *gets(char *dest) { int c = getchar(); char *p = dest; while (c != EOF && c != '\n') { *p++ = c; c = getchar(); } *p = '\0'; return dest; }读取输入行并将其返回:
void echo() { char buf[4]; gets(buf); puts(buf); } void call_echo() { echo(); }主程序:
int main() { printf("Type a string:"); call_echo(); return 0; }下面是这个程序的运行结果: 这里会发现char buf[4]太小了! 代码2:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFSIZE 256 int main(int argc, char *argv[]) { char prefix[BUFSIZE]; char next[BUFSIZE]; int i; float sum = 0.0; for (i = 1; i < argc; i++) { float x = atof(argv[i]); sum += x; if (i == 1) { sprintf(prefix, "%.4g", x); } else { sprintf(next, " + %.4g", x); strcat(prefix, next); printf("%s = %.4g\n", prefix, sum); } } return 0; }下面在ubuntu上的结果: @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 1e20 -1e20 3.14 1e+20 + -1e+20 = 0 1e+20 + -1e+20 + 3.14 = 3.14 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out -1e20 3.14 -1e+20 + 3.14 = -1e+20 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out -1e20 3.14 1e20 -1e+20 + 3.14 = -1e+20 -1e+20 + 3.14 + 1e+20 = 0 这说明浮点数在运算时有可能会造成精度损失,提醒我们在写程序时应注重数据类型和处理数的方式。
代码3: 将命令行上的十六进制数字序列转换为字符串,以\n结尾:
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { unsigned long dig = strtoul(argv[i], NULL, 16); putchar((char) dig); } putchar('\n'); return 0; }输入参数:30 31 32 33 34 35 36 37 38 39 输出为:0123456789
代码4: 存入数据的地址与上一个数据的地址有关,并且会影响下一个数据的地址
#include <stdlib.h> #include <stdio.h> #include <unistd.h> static void show_pointer(void *p, char *descr) { // printf("Pointer for %s at %p\n", descr, p); printf("%s\t%p\t%lu\n", descr, p, (unsigned long) p); } char big_array[1L<<24]; /* 16 MB */ //char huge_array[1L<<31]; /* 2 GB */ char huge_array[1L<<30];/* 1 GB */ int global = 0; int useless() { return 0; } int main () { void *p1, *p2, *p3, *p4; int local = 0; p1 = malloc(1L << 28); p2 = malloc(1L << 8); //p3 = malloc(1L << 32); p3 = malloc(1L << 16); p4 = malloc(1L << 8); show_pointer((void *) big_array, "big array"); show_pointer((void *) huge_array, "huge array"); show_pointer((void *) &local, "local"); show_pointer((void *) &global, "global"); show_pointer((void *) p1, "p1"); show_pointer((void *) p2, "p2"); show_pointer((void *) p3, "p3"); show_pointer((void *) p4, "p4"); show_pointer((void *) useless, "useless"); show_pointer((void *) exit, "exit"); show_pointer((void *) malloc, "malloc"); return 0; }下面运行结果: gec@ubuntu:/mnt/hgfs/share/csapp_code$ gcc locate.c gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out big array 0x4804a060 1208262752 huge array 0x804a060 134520928 local 0xbfcc9fdc 3217858524 global 0x804a044 134520900 p1 0xa7545008 2807320584 p2 0x49a67008 1235644424 p3 0x49a67110 1235644688 p4 0x49a77118 1235710232 useless 0x80484b6 134513846 exit 0x8048370 134513520 malloc 0x8048350 134513488
代码5: 深度递归示例:
#include <stdio.h> #include <stdlib.h> int recurse(int x) { int a[1<<15]; /* 4 * 2^15 = 64 KiB */ printf("x = %d. a at %p\n", x, a); a[0] = (1<<14)-1; a[a[0]] = x-1; if (a[a[0]] == 0) return -1; return recurse(a[a[0]]) - 1; } int main(int argc, char *argv[]) { int x = 100; if (argc > 1) x = atoi(argv[1]); int v = recurse(x); printf("x = %d. recurse(x) = %d\n", x, v); return 0; }不带参数 x = 100. a at 0xbfd3f8b0 x = 99. a at 0xbfd1f890 x = 98. a at 0xbfcff870 x = 97. a at 0xbfcdf850 x = 96. a at 0xbfcbf830 x = 95. a at 0xbfc9f810 x = 94. a at 0xbfc7f7f0 x = 93. a at 0xbfc5f7d0 x = 92. a at 0xbfc3f7b0 x = 91. a at 0xbfc1f790 x = 90. a at 0xbfbff770 x = 89. a at 0xbfbdf750 x = 88. a at 0xbfbbf730 x = 87. a at 0xbfb9f710 x = 86. a at 0xbfb7f6f0 x = 85. a at 0xbfb5f6d0 x = 84. a at 0xbfb3f6b0 x = 83. a at 0xbfb1f690 x = 82. a at 0xbfaff670 x = 81. a at 0xbfadf650 x = 80. a at 0xbfabf630 x = 79. a at 0xbfa9f610 x = 78. a at 0xbfa7f5f0 x = 77. a at 0xbfa5f5d0 x = 76. a at 0xbfa3f5b0 x = 75. a at 0xbfa1f590 x = 74. a at 0xbf9ff570 x = 73. a at 0xbf9df550 x = 72. a at 0xbf9bf530 x = 71. a at 0xbf99f510 x = 70. a at 0xbf97f4f0 x = 69. a at 0xbf95f4d0 x = 68. a at 0xbf93f4b0 x = 67. a at 0xbf91f490 x = 66. a at 0xbf8ff470 x = 65. a at 0xbf8df450 x = 64. a at 0xbf8bf430 x = 63. a at 0xbf89f410 x = 62. a at 0xbf87f3f0 x = 61. a at 0xbf85f3d0 x = 60. a at 0xbf83f3b0 x = 59. a at 0xbf81f390 x = 58. a at 0xbf7ff370 x = 57. a at 0xbf7df350 x = 56. a at 0xbf7bf330 x = 55. a at 0xbf79f310 x = 54. a at 0xbf77f2f0 x = 53. a at 0xbf75f2d0 x = 52. a at 0xbf73f2b0 x = 51. a at 0xbf71f290 x = 50. a at 0xbf6ff270 x = 49. a at 0xbf6df250 x = 48. a at 0xbf6bf230 x = 47. a at 0xbf69f210 x = 46. a at 0xbf67f1f0 x = 45. a at 0xbf65f1d0 x = 44. a at 0xbf63f1b0 x = 43. a at 0xbf61f190 x = 42. a at 0xbf5ff170 x = 41. a at 0xbf5df150 x = 40. a at 0xbf5bf130 x = 39. a at 0xbf59f110 x = 38. a at 0xbf57f0f0 段错误 (核心已转储) 输入参数如 20 x = 20. a at 0xbfb0c910 x = 19. a at 0xbfaec8f0 x = 18. a at 0xbfacc8d0 x = 17. a at 0xbfaac8b0 x = 16. a at 0xbfa8c890 x = 15. a at 0xbfa6c870 x = 14. a at 0xbfa4c850 x = 13. a at 0xbfa2c830 x = 12. a at 0xbfa0c810 x = 11. a at 0xbf9ec7f0 x = 10. a at 0xbf9cc7d0 x = 9. a at 0xbf9ac7b0 x = 8. a at 0xbf98c790 x = 7. a at 0xbf96c770 x = 6. a at 0xbf94c750 x = 5. a at 0xbf92c730 x = 4. a at 0xbf90c710 x = 3. a at 0xbf8ec6f0 x = 2. a at 0xbf8cc6d0 x = 1. a at 0xbf8ac6b0 x = 20. recurse(x) = -20
代码6: 显示字节.打印数据的字节表示:
#include <stdio.h> /* $end show-bytes */ #include <stdlib.h> #include <string.h> /* $begin show-bytes */ typedef unsigned char *byte_pointer; //typedef char *byte_pointer; //typedef int *byte_pointer; void show_bytes(byte_pointer start, size_t len) { size_t i; for (i = 0; i < len; i++) printf("%p\t0x%.2x\n", &start[i], start[i]); printf("\n"); } void show_int(int x) { show_bytes((byte_pointer) &x, sizeof(int)); } void show_float(float x) { show_bytes((byte_pointer) &x, sizeof(float)); } void show_pointer(void *x) { show_bytes((byte_pointer) &x, sizeof(void *)); } /* $end show-bytes */ /* $begin test-show-bytes */ void test_show_bytes(int val) { int ival = val; //float fval = (float) ival; double fval = (double) ival; int *pval = &ival; printf("Stack variable ival = %d\n", ival); printf("(int)ival:\n"); show_int(ival); printf("(float)ival:\n"); show_float(fval); printf("&ival:\n"); show_pointer(pval); } /* $end test-show-bytes */ void simple_show_a() { /* $begin simple-show-a */ int val = 0x87654321; byte_pointer valp = (byte_pointer) &val; show_bytes(valp, 1); /* A. */ show_bytes(valp, 2); /* B. */ show_bytes(valp, 3); /* C. */ /* $end simple-show-a */ } void simple_show_b() { /* $begin simple-show-b */ int val = 0x12345678; byte_pointer valp = (byte_pointer) &val; show_bytes(valp, 1); /* A. */ show_bytes(valp, 2); /* B. */ show_bytes(valp, 3); /* C. */ /* $end simple-show-b */ } void float_eg() { int x = 3490593; float f = (float) x; printf("For x = %d\n", x); show_int(x); show_float(f); x = 3510593; f = (float) x; printf("For x = %d\n", x); show_int(x); show_float(f); } void string_ueg() { /* $begin show-ustring */ const char *s = "ABCDEF"; show_bytes((byte_pointer) s, strlen(s)); /* $end show-ustring */ } void string_leg() { /* $begin show-lstring */ const char *s = "abcdef"; show_bytes((byte_pointer) s, strlen(s)); /* $end show-lstring */ } void show_twocomp() { /* $begin show-twocomp */ short x = 12345; short mx = -x; show_bytes((byte_pointer) &x, sizeof(short)); show_bytes((byte_pointer) &mx, sizeof(short)); /* $end show-twocomp */ } int main(int argc, char *argv[]) { int val = 12345; if (argc > 1) { val = strtol(argv[1], NULL, 0); printf("calling test_show_bytes\n"); test_show_bytes(val); } else { printf("calling show_twocomp\n"); show_twocomp(); printf("Calling simple_show_a\n"); simple_show_a(); printf("Calling simple_show_b\n"); simple_show_b(); printf("Calling float_eg\n"); float_eg(); printf("Calling string_ueg\n"); string_ueg(); printf("Calling string_leg\n"); string_leg(); } return 0; }不带参数的运行结果 calling show_twocomp 0xbfa18b4c 0x39 0xbfa18b4d 0x30
0xbfa18b4e 0xc7 0xbfa18b4f 0xcf
Calling simple_show_a 0xbfa18b48 0x21
0xbfa18b48 0x21 0xbfa18b49 0x43
0xbfa18b48 0x21 0xbfa18b49 0x43 0xbfa18b4a 0x65
Calling simple_show_b 0xbfa18b48 0x78
0xbfa18b48 0x78 0xbfa18b49 0x56
0xbfa18b48 0x78 0xbfa18b49 0x56 0xbfa18b4a 0x34
Calling float_eg For x = 3490593 0xbfa18b30 0x21 0xbfa18b31 0x43 0xbfa18b32 0x35 0xbfa18b33 0x00
0xbfa18b30 0x84 0xbfa18b31 0x0c 0xbfa18b32 0x55 0xbfa18b33 0x4a
For x = 3510593 0xbfa18b30 0x41 0xbfa18b31 0x91 0xbfa18b32 0x35 0xbfa18b33 0x00
0xbfa18b30 0x04 0xbfa18b31 0x45 0xbfa18b32 0x56 0xbfa18b33 0x4a
Calling string_ueg 0x8048940 0x41 0x8048941 0x42 0x8048942 0x43 0x8048943 0x44 0x8048944 0x45 0x8048945 0x46
Calling string_leg 0x8048947 0x61 0x8048948 0x62 0x8048949 0x63 0x804894a 0x64 0x804894b 0x65 0x804894c 0x66
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 1073741824 calling test_show_bytes Stack variable ival = 1073741824 (int)ival: 0xbfd40020 0x00 0xbfd40021 0x00 0xbfd40022 0x00 0xbfd40023 0x40
(float)ival: 0xbfd40020 0x00 0xbfd40021 0x00 0xbfd40022 0x80 0xbfd40023 0x4e
&ival: 0xbfd40020 0x34 0xbfd40021 0x00 0xbfd40022 0xd4 0xbfd40023 0xbf
代码7: 返回整型数据的二次方:
#include <stdio.h> #include <stdlib.h> int sq(int x) { return x*x; } int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { int x = atoi(argv[i]); int sx = sq(x); printf("sq(%d) = %d\n", x, sx); } return 0; }有结果如下: @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 12 sq(12) = 144 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 65535 sq(65535) = -131071 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 40000 sq(40000) = 1600000000 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 50000 sq(50000) = -1794967296 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 400000 sq(400000) = 1086210048 @ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 500000 sq(500000) = 891896832 这例说明整型数据相乘时有可能会出现溢出问题,而造成结果不符合实际。 显然程序代码没有问题时,输入的数据是有范围的,如果不注重底层的这些要求,则可能会出现意想不到的结果。 代码8: 结构体的相关问题:
#include <stdio.h> #include <stdlib.h> typedef struct { int a[2]; double d; } struct_t; double fun(int i) { volatile struct_t s; s.d = 3.14; s.a[i] = 1073741824; /* Possibly out of bounds */ return s.d; /* Should be 3.14 */ } int main(int argc, char *argv[]) { int i = 0; if (argc >= 2) i = atoi(argv[1]); double d = fun(i); printf("fun(%d) --> %.10f\n", i, d); return 0; }运行结果如下: gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 0 fun(0) --> 3.1400000000 gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 1 fun(1) --> 3.1400000000 gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 2 fun(2) --> 3.1399998665 gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 3 fun(3) --> 2.0000006104 gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 4 fun(4) --> 3.1400000000 段错误 (核心已转储) 这例说明,结构体是一个存储区域,是有一定大小的,所以是可能出界的。 这提醒我们应该在做结构体时,要注意这类相关问题,否则可能会出现意想不到的问题。