#include
main()
{
printf("Hello, world\n");
}
a. #include < stdio.h>用于告诉编译器在本程序中包含标准输入/输出库的信息。
b. printf是一个用于打印输出的库函数。顺便指出,printf函数并不是C语言本身的一部分,C语言本身并没有定义输入输出功能。printf仅仅是标准库函数中的一个有用的函数而已,这些标准库函数在C语言程序中通常可以使用。但是,ANSI标准定义了printf函数的行为,因此对每个符合该标准的编译器和库来说,该函数的属性都是相同的。
c. 类似于\n的转义字符序列为表示无法输入的字符或不可见的字符提供了一种通用的可扩充的机制。
#include
/**<将输入复制到输出;版本1 */
main()
{
int c;
c = getchar();
while (c != EOF)
{
putchar(c);
c = getchar();
}
}
a. 关于int c。字符在键盘、屏幕或其他的任何地方无论以什么形式表现,它在机器内部都是以位模式存储的。char类型专门用于存储这种字符型数据,当然任何整型也可以用于存储字符型数据。
#include
main()
{
printf("%d",EOF);
}
考虑一个更精炼的版本:
#include
/**<将输入复制到输出;版本2 */
main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
a. 关于(c = getchar()) != EOF。这段程序表示:在while内部,首先读一个字符,并将其赋值给c,然后检测该字符是否为文件结束标志。
#include
/**< 统计输入的字符数;版本1 */
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%1d\n", nc);
}
a. 程序使用long类型的变量存放计数值。长整型至少占用32位存储单元。在某些机器上long和int类型的长度相同,但在一些机器上,int型的可能只有16位存储单元的长度。使用double型可以处理更大的数字。
#include
/**< 统计输入的字符数;版本2 */
main()
{
double nc;
for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);
}
a. 所有工作都在条件语句部分与增加布长部分完成了,但C语言的语法要求for的循环语句必须有一个循环体,因此用单独的分号代替。单独的分号称为空语句。
#include
/**< 行计数 */
main()
{
int c, nl;
nl = 0;
while ((c = getchar()) != EOF)
if (c == '\n')
++nl;
printf("%d\n", nl);
}
a. 行计数即统计有多少个换行符。
#include
#define BLANK ' '
/** 练习 1-9
*
* 编写一个将输入复制到输出的程序,
* 将其中连续的多个空格用一个空格代替。
*
*
*/
main()
{
int c, last;
while ((c = getchar()) != EOF)
{
if (c != BLANK || last != BLANK)
putchar(c);
last = c;
}
}
#include
#define BACKSLASH '\\'
#define BACKSPACE '\b'
#define TAB '\t'
/** 练习 1-10
*
* 编写一个将输入复制到输出的程序,
* 将制表符替换为\t,
* 将回退符替换为\b,
* 将反斜杠替换为\\,
* 将制表符和回退符以可见的方式显示出来。
*/
main()
{
int c;
while ((c = getchar()) != EOF)
{
if (c == BACKSLASH)
printf("\\\\");
else if (c == BACKSPACE)
printf("\b");
else if (c == TAB)
printf("\t");
else
putchar(c);
}
}
#include
#define IN 1 /**< 在单词内 */
#define OUT 0 /**< 在单词外 */
/**< 统计输入的行数、单词数与字符数 */
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", nl, nw, nc);
}
a. 关于IN和OUT。使用IN和OUT,使得程序更具有可读性。
#include
/** 练习 1-12
*
* 编写一个程序,
* 以每行一个单词的形式打印其输入。
*
*
*/
main()
{
int c, INSPACE; /**< INSPACE记录之前是否位于单词中。0为在,1为不在。 */
INSPACE = 0;
while ((c = getchar()) != EOF)
{
if (c == '\t' || c == '\n' || c == ' ')
{
if (INSPACE == 0)/**< 之前在单词中,而现在不在 */
putchar('\n');
INSPACE = 1;
}
else
{
INSPACE = 0;
putchar(c);
}
}
}
#include
/**< 计算x的y次方 */
int power(int x, int y);
main()
{
int i;
for (i = 0; i < 10; ++i)
printf("%d\t%d\t%d\n", i, power(2, i), power(-3, i));
return 0;
}
int power(int x, int y)
{
int i, p;
p = 1;
for (i = 1; i <= y; ++i)
p = p * x;
return p;
}
a. 区分函数声明(declaration)与函数定义(define)。定义表示创建变量或分配储存单元,而声明指的是说明变量的性质,但并不分配存储单元。在上面的例子中,出现在main函数之前的语句是声明语句,声明参数的类型、名字以及该函数返回结果的类型。这种声明被称为函数原型。出现在main函数后面的语句是函数定义语句。
#include
#define MAXLINE 1000 /**< 允许的输入行的最大长度 */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/**< 读入一组文本行,并把其中最长的文本行打印出来 */
main()
{
int len; /**< 当前行长度 */
int max; /**< 目前发现的最大行长度 */
char line[MAXLINE]; /**< 当前输入行 */
char longest[MAXLINE]; /**< 用于保存最长的行 */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
{
if (len > max)
{
max = len;
copy(longest, line);
}
}
if (max > 0) /**< 存在这样的最长行 */
printf("%s", longest);
return 0;
}
/**< 将一行读入s中并返回其长度 */
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;
}
/**< 将from复制到to */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
a. 关于'\0'。getline函数将空字符插入到它创建的数组的末尾,以标记字符串的结束。该约定已经被C语言采用。例如,挡在C语言程序中出现"hello\n"的字符串常量时,它将以字符数组的形式存储,数组的各元素分别存储字符串的各个字符,并以'\0'标记结束。
h | e | l | l | o | \n | \0 |
#include
#define MAXLINE 1000
#define CRITICALVALUE 80
int getline(char line[], int maxline);
/** 练习 1-17
*
* 打印长度大于80个字符的所有输入行
*
*/
main()
{
int c;
int len = 0;
char line[MAXLINE];
while ((len = getline(line,MAXLINE)) > 0)
if (len > CRITICALVALUE)
printf("%s", line);
return 0;
}
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;
}
#include
#define MAXLINE 1000
int getline(char line[], int maxline);
void reverse(char line[], int length);
/** 练习 1-19
*
* 编写函数reverse(s),将字符串中的字符顺序颠倒过来。
* 每次颠倒一个输入行中的字符顺序。
*/
main()
{
int len;
char line[MAXLINE];
while ((len = getline(line, MAXLINE)) > 0)
{
reverse(line, len);
printf("%s", line);
}
return 0;
}
int getline(char s[], int lim)
{
int c, len;
for (len = 0; len < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++len)
s[len] = c;
if (c == '\n')
{
s[len] = c;
++len;
}
s[len] = '\0';
return len;
}
void reverse(char s[], int len)
{
int i;
for (i = 0; i < len / 2; ++i)
{
int tmp = s[i];
s[i] = s[len - 2 - i];
s[len - 2 - i] = tmp;
}
}
#include
#define MAXLINE 1000 /**< 允许的输入行的最大长度 */
int max;
char line[MAXLINE];
char longest[MAXLINE];
int getline();
void copy();
/**< 读入一组文本行,并把其中最长的文本行打印出来:特殊版本 */
main()
{
int len; /**< 当前行长度 */
extern int max; /**< 目前发现的最大行长度 */
extern char longest[MAXLINE]; /**< 用于保存最长的行 */
max = 0;
while ((len = getline()) > 0)
{
if (len > max)
{
max = len;
copy();
}
}
if (max > 0) /**< 存在这样的最长行 */
printf("%s", longest);
return 0;
}
/**< 读入并返回其长度 */
int getline(void)
{
int c, i;
extern char line[];
for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
line[i] =c;
if (c == '\n')
{
line[i] = c;
++i;
}
line[i] = '\0'; /**< 标志字符串的结束 */
return i;
}
/**< 复制 */
void copy(char to[], char from[])
{
int i;
extern char line[], longest[];
i = 0;
while ((longest[i] = line[i]) != '\0')
++i;
}
a. 函数在使用外部变量之前,必须要知道外部变量的名字。要达到该目的,一种方式是在函数中使用extern类型的声明。某些情况下可以省略extern声明。在源文件中,如果外部变量的定义出现在使用它的函数之前,那么在那个函数中就没有必要使用extern声明。因此,main、getline、copy中的几个extern声明都是多余的。在通常的做法中,所有外部变量的定义都放在源文件的开始处,这样就可以省略extern声明。