本章例程

程序1.1 重排字符

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 #define MAX_COLS 20
 6 #define MAX_INPUT 1000
 7 
 8 int read_column_numbers(int columns[], int max);
 9 void rearrange(char * output, char const * input,
10                int n_columns, int columns[]);
11 
12 int main(void)
13 {
14     int n_columns;
15     int columns[MAX_COLS];
16     char input[MAX_INPUT];
17     char output[MAX_INPUT];
18 
19     n_columns = read_column_numbers(columns, MAX_COLS);
20 
21     while(gets(input) != NULL){
22         printf("Original input: %s\n", input);
23         rearrange(output, input, n_columns, columns);
24         printf("Rearrange output: %s\n", output);
25     }
26 
27     return EXIT_SUCCESS;
28 }
29 
30 int read_column_numbers(int columns[], int max)
31 {
32     int num = 0;
33     int ch;
34 
35     while(num < max && (scanf("%d", &columns[num])) == 1
36           && columns[num] >= 0)
37         num += 1;
38 
39     if(num % 2 != 0){
40         puts("last column number is not paired.");
41         return EXIT_FAILURE;
42     }
43 
44     while((ch = getchar()) != EOF && ch != '\n')
45         ;
46     return num;
47 }
48 
49 void rearrange(char * output, char const * input,
50                int n_columns, int columns[])
51 {
52     int col;
53     int output_col;
54     int len;
55 
56     len = strlen(input);
57     output_col = 0;
58 
59     for(col = 0; col < n_columns; col += 2){
60         int nchars = columns[col+1] - columns[col] + 1;
61         
62         if(columns[col] >= len || output_col >= MAX_INPUT - 1)
63             break;
64         if(output_col + nchars > MAX_INPUT - 1)
65             nchars = MAX_INPUT - 1 - output_col;
66 
67         strncpy(output + output_col, input + columns[col], nchars);
68         output_col += nchars;
69     }
70     output[output_col] = '\0';
71 }

本章问题

1.C is a free-form languague,which means that there are no rules regarding how programs must look.Yet the sample program followed specific spacing rules.why do you think this is?

(C是一种自由形式的语言,这意味着没有规则规定它应该怎样编程,但是本章的例程仍然遵循了一定的空白规则,对此你有何看法?)

answer : To make the program easier to read, which in turn makes it easier to maintain later.

(使得程序更容易阅读,便于以后的维护)

 

2.What is the advantage of putting declaration, such as function prototypes,in header files and then using #include to bring the declarations into the source files where they are needed?

(声明有什么优点?比如函数原型,在头文件使用#include声明并在源文件需要的时候包含它们)

answer : The declaration needs to be written only once,which makes it easier to maintain if modification(修改) are needed later,Also,writing it only once eliminates(消除) the chance that additional copies(副本) are written differently from each other.

(声明只需要写一次,能使代码在日后需要修改的时候更容易维护,只写一次可以消除多个副本不一致的情况)

 

 

3.What is the advantage of using #define to give names to literal(字面的) constants?

(用#define 给字面常量命名有什么好处?)

answer : It is easier to see what a named constant represents,if it is well named,than a literal constant,which merely(仅仅) displays its value.

(如果是好的命名常量比仅仅显示值的字面常量更容易看出常量代表的意义)

 

4.What format string would you use with printf in order to print a decimal integer,a string,and a floating-point value,in that order?Separate the values from one another with a space,and end the output with a newline character.

(用printf把整数,字符串,浮点数依次打印出来应该用什么格式,分别把它们用空格隔开,并且在结尾输出换行符)

answer : 

"%d %s %g\n"

 

5.Write the scanf statement needed to read two integers,called quantity and price,followed by a string,which should be stored in a character array called department.

(写一个scanf语句,需要读取质量和价格两个整型参数,后面还要读取一个字符串,用一个字符数组在存储一个叫做部门的参数)

answer :

scanf("%d %d %s",&quantity, &price,department);

 

6.There are no checks made on the validity(有效性) of an array subscript(下标) in C,why do you think this obvious safety measure was omitted(省略) from the language?

(在C语言中对数组下标的有效性不做检查,你认为为什么这个显然的安全措施在语言中被省略了呢?)

answer : The programmer can put in subscript checks where they are needed;in places where the subscript is already known to be correct(for example,from having been checked earlier),there is no overhead expended(花费) in checking it again.But the real reason they are omitted is the fact that subscripts are implemented(工具) as pointer expressions,which are described in chapter 8.

(程序员可以自己在他们需要的地方对下标做检查,下标在适当的位置已经知道是对的,比如说过早的检查,不用在消耗开支去再次检查,不过真正省略下标检查的原因是因为下标是个指针表达式,将在第八章描述它)

 

7.The rearrange program described in the chapter contains the statement:

strncpy(output + output_col, input + columns[col], nchars);

the strcpy function takes only two arguments,so the number of characters it copies is determined by the string specified(指定) by the second argument,what would be the effect of replacing the strncpy function call with a call to strcpy in this program?

(strcpy 这个函数只需要两个参数,所以它实际复制的字符由第二个参数指定,在这个程序中,如果用strcpy替换strncpy会产生什么影响?)

answer : More characters would be copied than are actually needed;however,the output_col would be updated properly,so the next range of characters would be copied into the output array at the proper place,replacing any extra characters from the preceding(在之前) operation.the only potential(潜在的) problem is that the unbounded strcpy might copy more characters into the output array than it has room to hold,destroying some other variables.

(将会比实际需要复制的字符多,然而,由于output_col的值一直在更新,所以下个字符的范围仍然会在合适的地方,会替代前面操作中额外复制的字符,唯一潜在的问题是strcpy可能从output复制更多的字符而没有边界,超过数组本身的容量,会销毁其他的变量)

 

8.The rearrange program contains the statement

while(gets(input) != NULL )

what might go wrong with this code?

(下面的代码可能会产生什么问题?)

answer : When an array is passed as a function argument,the function has no way of knowing its size,Therefore,gets has no way to prevent(预防) a very long input line from overflowing the input array,the fgets function,which requires that the array size be passed as an argument,does not have this problem.

(当一个数组作为函数参数被通过时,这个函数不知道数组的长度,因此,gets没法预防一个非常长的输入行的溢出,而fgets这个函数,它的参数中要求有数组的长度,因此不会出现这种情况)

 

本章练习

1.The "Hello world!" program is often the first C program that a student of c writes.It prints hello world! followed by a newline on the standard output.This trivial(微不足道的) program is a good one to use when figuring out how to run the c compiler on your particular system.

(hello world!程序经常被作为学生用c写的第一个c语言程序,它打印出一行hello world!以换行符结尾的标准输出,这个微不足道的程序用来摸索特殊系统怎样编译c程序是很好的)

#include <stdio.h>

int main(void)
{
     printf("hello world!");
     return 0;
}

 

2.Write a program that reads lines from the standard input.Each line is printed on the standard output preceded(先于) by its line number.Try to write the program so that it has no built-in limit on how long a line it can handle.

(写一个程序,从标准输入中读取行数,每一行在标准输出中先打印行号再打印出来,尝试让这个程序能够处理的一行不受限制)

#include <stdio.h>

int main(void)
{
    int ch;
    int line = 0;
    int at_beginning = 1;
    while((ch = getchar()) != EOF){
        if(at_beginning == 1){
            at_beginning = 0;
            line += 1;
            printf("%d", line);
        }
        putchar(ch);
        if(ch == '\n')
            at_beginning = 1;
    }
    return EXIT_SUCCESS;   
}

 

3.Write a program that reads characters from the standard input and writes them to the standard output.It should also compute a checksum and write it out after the characters .The checksum is computed in a signed char variable that is initialized to -1.As each character is read from the standar input,it is added to the checksum.Any overflow from the checksum variable is ignored.When all of the character have been written,the checksum is then written as a decimal integer,which may be negative.Be sure to follow the checksum with a new-line.On computers that use ASCII,running your program on a file containning the words "hello world",followed by a newline should produce the following output:

(写一个程序从标准输入中读取字符之后在标准输出中写出,同时应该计算checksum并把它写在字符的后面,checksum用一个signed char变量计算并初始化为-1,每从标准输入读取一个字符,checksum的值就增加,checksum变量的值溢出部分忽略,当所有的字符被写入时,checksum作为一个整型数写出,它可能是个负数,确定在checksum的后面加个换行符,计算时使用ASCII码,运行你的程序包含hello world!后面的输出为)

Hello world!
102
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char checksum = -1;
    int ch;

    while( (ch = getchar()) != EOF && ch != '\n'){
        putchar(ch);
        checksum += ch;
    }
    printf("\n%d\n",checksum);
    
    return 0;
}

 

4.Write a program that reads input lines one by one until end of file is reached.determines the length of each input line,and then prints out only the longest line that was found,To simplify(简化) matters,you may assume that no input line will be longer than 1000 characters.

(写一个程序从标准输入中一行一行读取,直到遇到文件结尾符,计算每个输入行的长度,然后找到最长的一行并打印出来,为了使情况简单,你需要假定输入的行最大字符不超过1000)

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 
 5 #define MAX 1000
 6 
 7 int main(void)
 8 {
 9     int length = 0;
10     char longest[MAX];
11     char input[MAX];
12 
13     while( gets(input) != NULL ){
14         int len = strlen(input);
15         
16         if(len > MAX){
17             printf("input longer than 1000");
18             return -1;
19         }
20         
21         if(length < len){
22             length = len;
23             strcpy(longest,input);
24         }
25     }
26 
27     if(length > 0)
28         printf("the longest string %s length is %d\n",longest,length);
29     
30     return 0;
31 }

 

 

注意:我在第23行进行字符串的复制的时候犯了一个小错误,这牵涉到字符数组的初始化与赋值的问题,不能直接给字符数组赋值,如果直接写:

longest = input;

程序是通不过的,如果longest变量为char *类型,那么程序可能可以通过,不过longest会随着input的变化而变化,if条件句对它失效:

char * longest;
char input[];
longest = input;

 

5.The statement

if(columns[col] >= len ...)
    break;

in the rearrange program stops copying ranges of characters as soon as range is encountered(遇到问题) that is past the end of the input line,This statement is correct only if the ranges are entered in increasing order,which may not be the case,modify the rearrange function so that it will work correctly even if the ranges are not entered in order.

(rearrange函数中的语句在输入行的长度少于列范围时就退出,这条语句只有在列范围是递增的情况下正确,然而事实并不一定如此,(比如3,4,1,2,-1 或者 3 5 6 4 -1)修改rearrange函数使得在任何情况下都正确)

 1 void rearrange(char * output, char const * input,
 2                int n_columns, int columns[])
 3 {
 4     int col;
 5     int output_col;
 6     int len;
 7 
 8     len = strlen(input);
 9     output_col = 0;
10 
11     for(col = 0; col < n_columns; col += 2){
12         int nchars = columns[col+1] - columns[col] + 1;
13         
14         if(output_col >= MAX_INPUT - 1)
15             break;
16 
17         if(nchars <= 1){
18             printf("columns error,begin small than end!\n");
19             break;
20         }
21 
22         if(columns[col] >= len)
23             continue;
24 
25         if(output_col + nchars > MAX_INPUT - 1)
26             nchars = MAX_INPUT - 1 - output_col;
27 
28         strncpy(output + output_col, input + columns[col], nchars);
29         output_col += nchars;
30     }
31     output[output_col] = '\0';
32 }

 

6.Modify the rearrange program to remove the restriction(限制) that an even(不变的) number of column values must be read initially(最初),If an odd(奇数) number of values are read,the last valued indicates the start of the final range of characters,characters from here to the end of the input string are copied to the output string.

(修改rearrange程序,去除最开始读取到column数组的数必须是奇数的限制,如果读取的为奇数个,最后一个值作为最后一组字符串的开始,到输入字符串的末尾被复制到输出字符串中)

//去掉read_column_numbers函数中的判断奇偶语句

void rearrange(char * output, char const * input,
               int n_columns, int columns[])
{
    int col;
    int output_col;
    int len;

    len = strlen(input);
    output_col = 0;

    for(col = 0; col < n_columns; col += 2){
        int nchars;
        
        if(output_col >= MAX_INPUT - 1)
            break;
        if(columns[col] >= len)
            continue;
        
        if(col+1 >= n_columns)
            nchars = len - columns[col];
        else
            nchars = columns[col+1] - columns[col] + 1;
        
        if(nchars <= 1){
            printf("columns error,begin small than end!\n");
            break;
        }
        
        if(output_col + nchars > MAX_INPUT - 1)
            nchars = MAX_INPUT - 1 - output_col;

        strncpy(output + output_col, input + columns[col], nchars);
        output_col += nchars;
    }
    output[output_col] = '\0';
}