《The C Programming Language, 2nd Edition》K&R Chapter 1 - A Tutorial Introduction 笔记

printf

printf("\c");MinGW gcc输出c。(\c不是转义序列)

printf("%6d", -17);,输出□□□-17,其中□表示空格。(%6d中6表示最少打印宽度,6是正数表示右对齐,如果是负数则表示左对齐)

printf("%.0f", -17.8);,输出-18。(%.0f中.0表示小数精度)

%o表示8进制,%x表示16进制,%%表示%。

变量类型

int通常为16位或32位,16位取值范围为-32768 ~ +32767。

long至少为32位,通常为32位。

float通常为32位,至少6位有效数字,取值范围1038+1038-10^{38} \sim +10^{38}

常量

文件结束符EOF,在<stdio.h>中定义,int类型,值在char的取值范围之外。

'A'是字符常量,本质是整数,值取决于编译器认为的源文件字符集。在ASCII中,'A'为65,'\n'为10。在任何字符集中'0'、'1'、'2'、...、'9'都是连续递增的。

运算符

如果算术运算符所有操作数都为整型,则执行整型运算(如舍位除法)。其中一个操作数为浮点,则执行浮点运算。

nl = nw = nc = 0;的执行顺序为nl = (nw = (nc = 0));

||和&&是短路运算符。

定义与声明

定义包含声明,定义会分配内存,而声明不会。

ANSI C之前,函数原型声明包含返回值类型,不包含形参列表,如int power();

函数在调用之前必须存在函数原型声明。
因此,ANSI C之前,如果一个函数,缺省函数原型声,编译器认为这个函数隐式声明返回值类型为int。

ANSI C兼容旧式函数原型声明。

ANSI C支持函数原型声明包含形参列表,其中形参名是可选的。如int power(int, int);

当函数原型声明中包含形参列表时,编译器会检查实参列表,并进行适当的强转。不包含时,编译器不检查实参列表,整数强转为int,浮点强转为double。

在函数原型声明中,不包含形参列表与形参列表为void的含义不同,前者表示编译器不检查实参列表,后者表示编译器检查实参列表,如果实参存在,则报错。

ANSI C之前,函数定义的语法与ANSI C差异较大。ANSI C兼容旧式函数定义。

在函数外部定义的变量称为外部变量。
外部变量定义后,外部变量是静态的(在程序运行期间一直存在)。
在外部变量定义之前访问它,必须使用extern显式声明。在定义之后访问它,可选使用extern显式声明。
访问在其他文件中定义的外部变量(前提是外部链接),必须使用extern显式声明。

函数

return;不返回有用的值,而不是不返回值。例如:

#include <stdio.h>

int func()
{
    return;
}

main()
{
    printf("%d", func());
}

MinGW gcc输出1

函数的参数是值传递的,保存在临时变量形参中,修改形参的值不影响实参的值。

在函数调用期间存在,函数退出时销毁的局部变量称为自动变量。
auto变量是自动变量,static变量是静态变量,反之不成立。

例程

复制文件

#include <stdio.h>
main()
{
    int c;

    while ((c = getchar()) != EOF)
        putchar(c);
}

统计字符数

#include <stdio.h>
main()
{
    double nc;

    for (nc = 0; getchar() != EOF; ++nc)
         ;
    printf("%.0f\n", nc);
}

统计行数

#include <stdio.h>
main()
{
    int c, nl;

    nl = 1;
    while ((c = getchar()) != EOF)
        if (c == '\n')
            ++nl;
    printf("%d\n", nl);
}

统计单词数(假设不包含空格、制表符、换行符的字符序列为单词)

  1. 起始state为OUT。
  2. 当遇到非空格、制表符、换行符字符时,state置IN,单词数自增。
  3. 当遇到空格、制表符、换行符时,state置OUT。
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
main()
{
    int c, nl, nw, nc, state;

    state = OUT;
    nl = nw = nc = 0;
    while ((c = getchar()) != EOF) {
        ++nc;
        if (c == '\n')
            ++nl;
        if (c == ' ' || c == '\n' || c = '\t')
            state = OUT;
        else if (state == OUT) {
            state = IN;
            ++nw;
        }
    }
    printf("%d %d %d\n", nl, nw, nc);
}

统计各个数字、空白符及其他字符出现的次数

#include <stdio.h>
/* count digits, white space, others */
main()
{
    int c, i, nwhite, nother;
    int ndigit[10];

    nwhite = nother = 0;
    for (i = 0; i < 10; ++i)
        ndigit[i] = 0;

    while ((c = getchar()) != EOF)
        if (c >= '0' && c <= '9')
            ++ndigit[c-'0'];
        else if (c == ' ' || c == '\n' || c == '\t')
            ++nwhite;
        else
            ++nother;

    printf("digits =");
    for (i = 0; i < 10; ++i)
        printf(" %d", ndigit[i]);
    printf(", white space = %d, other = %d\n",
        nwhite, nother);
}

幂函数

#include <stdio.h>

int power(int m, int n);

/* test power function */
main()
{
    int i;

    for (i = 0; i < 10; ++i)
        printf("%d %d %d\n", i, power(2,i), power(-3,i));
    return 0;
}

/* power: raise base to n-th power; n >= 0 */
int power(int base, int n)
{
    int i, p;

    p = 1;
    for (i = 1; i <= n; ++i)
        p = p * base;
    return p;
}

打印最长的行

#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */

int getline(char line[], int maxline);
void copy(char to[], char from[]);

/* print the longest input line */
main()
{
    int len; /* current line length */
    int max; /* maximum length seen so far */
    char line[MAXLINE]; /* current input line */
    char longest[MAXLINE]; /* longest line saved here */

    max = 0;
    while ((len = getline(line, MAXLINE)) > 0)
        if (len > max) {
            max = len;
            copy(longest, line);
        }
    if (max > 0) /* there was a line */
        printf("%s", longest);
    return 0;
}

/* getline: read a line into s, return length */
int getline(char s[],int lim)
{
    int c, i;

    for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
    int i;
    i = 0;
    while ((to[i] = from[i]) != '\0')
        ++i;
}