24 / 07 / 11

「一生一芯」Learn C the hard way - Ex 10

练习 10:字符串数组和循环

#include <stdio.h> int main(int argc, char *argv[]) { int i = 0; // go through each string in argv // why am I skipping argv[0]? for(i = 1; i < argc; i++) { printf("arg %d: %s\n", i, argv[i]); } // let's make our own array of strings char *states[] = { "California", "Oregon", "Washington", "Texas" }; int num_states = 4; for(i = 0; i < num_states; i++) { printf("state %d: %s\n", i, states[i]); } return 0; }
make ex10 cc -Wall -g -c ex10.c -o ex10.o cc -o ex10 ex10.o ⮞ ./ex10 aaaa bbbb cccc dddd arg 1: aaaa arg 2: bbbb arg 3: cccc arg 4: dddd state 0: California state 1: Oregon state 2: Washington state 3: Texas

i初始化为0看看会发生什么。是否也需要改动argc,不改动的话它能正常工作吗?为什么下标从0开始可以正常工作?

⮞ ./ex10 a b c d arg 0: ./ex10 arg 1: a arg 2: b arg 3: c arg 4: d state 0: California state 1: Oregon state 2: Washington state 3: Texas

argc 的第一项是 ./ex10 本身哈哈哈哈哈。

num_states改为错误的值使它变大,来看看会发生什么。

⮞ ./ex10 a b c d arg 0: ./ex10 arg 1: a arg 2: b arg 3: c arg 4: d state 0: California state 1: Oregon state 2: Washington state 3: Texas Segmentation fault state 4: (null) ==5228== Invalid read of size 1 ==5228== at 0x4851E56: strlen (vg_replace_strmem.c:505) ==5228== by 0x48DFD30: __vfprintf_internal (vfprintf-internal.c:1517) ==5228== by 0x48C979E: printf (printf.c:33) ==5228== by 0x109235: main (ex10.c:21) ==5228== Address 0x9579af4c8feb2d00 is not stack'd, malloc'd or (recently) free'd ==5228== ==5228== ==5228== Process terminating with default action of signal 11 (SIGSEGV) ==5228== General Protection Fault ==5228== at 0x4851E56: strlen (vg_replace_strmem.c:505) ==5228== by 0x48DFD30: __vfprintf_internal (vfprintf-internal.c:1517) ==5228== by 0x48C979E: printf (printf.c:33) ==5228== by 0x109235: main (ex10.c:21) ==5228== ==5228== HEAP SUMMARY: ==5228== in use at exit: 1,024 bytes in 1 blocks ==5228== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated

不要越界喔。

附加题 1

弄清楚在for循环的每一部分你都可以放置什么样的代码。

附加题 2

查询如何使用','(逗号)字符来在for循环的每一部分中,';'(分号)之间分隔多条语句。

在 C 语言中,for 循环具有以下语法结构:

for (initialization; condition1, condition2; increment) { // Loop body }

在这个结构中:

  1. **初始化部分 (initialization)**:在循环开始前执行一次,通常用于声明和初始化控制变量。

  2. **条件部分 (condition)**:在每次迭代前进行检查,如果条件为真,继续执行循环体;如果条件为假,退出循环。

  3. **增量部分 (increment)**:在每次循环体执行后执行一次,用于更新控制变量。

  4. **循环体 (loop body)**:在每次迭代中执行的代码块。

附加题 3

查询NULL是什么东西,尝试将它用做states的一个元素,看看它会打印出什么。

在 C 语言中,NULL 是一个宏,它通常定义为一个指向地址为 0 的指针。它表示一个空指针,即不指向任何对象或函数的指针。使用 NULL 可以避免指针指向未初始化或无效的地址,减少了程序出错的风险。

char *states[] = { "California", "Oregon", "Washington", NULL, "Texas" }; int num_states = 5; for(i = 0; i < num_states; i++) { printf("state %d: %s\n", i, states[i]); }
⮞ ./ex10 arg 0: ./ex10 state 0: California state 1: Oregon state 2: Washington state 3: (null) state 4: Texas

附加题 4

看看你是否能在打印之前将states的一个元素赋值给argv中的元素,再试试相反的操作。

有点不理解题目的表述,如果直接在打印 argv 前将 states 赋值给它,那么必然会报错,因为此时 states 还没有被申明。如果将申明移动到打印前,尝试如下:

⮞ ./ex10 state 0: California state 1: Oregon state 2: Washington state 3: Texas ⮞ ./ex10 a b c d arg 1: California arg 2: b arg 3: c arg 4: d state 0: California state 1: Oregon state 2: Washington state 3: Texas

相反操作如下:

⮞ make ex10 cc -Wall -g -c ex10.c -o ex10.o cc -o ex10 ex10.o ./ex10 state 0: California state 1: (null) state 2: Washington state 3: Texas ./ex10 aa bb cc arg 1: aa arg 2: bb arg 3: cc state 0: California state 1: aa state 2: Washington state 3: Texas