为了加强C语言基础,觉得阅读这本优秀的书籍。首先,我会总结一些我认为的要点,如果有优秀的例子和题,我也觉得需要记录下来。
Exercise 1-1. Run the ``hello, world'' program on your system. Experiment with leaving out parts of the program, to see what error messages you get.
答:
#include
int main(void)
{
printf("hello, world\n");
return 0;
}
linux 下,可以这样执行:
gcc -W -Wall -ansi -pedantic -o hello hello.c
如此会得到一个hello的输出,直接执行可以得到结果。
转义字符
|
意义
|
ASCII码值(十进制)
|
\a
|
响铃(BEL)电脑会发出声音
|
007
|
\b
|
退格(BS) ,将当前位置移到前一列
|
008
|
\f
|
换页(FF),将当前位置移到下页开头
|
012
|
\n
|
换行(LF) ,将当前位置移到下一行开头
|
010
|
\r
|
回车(CR) ,将当前位置移到本行开头
|
013
|
\t
|
水平制表(HT) (跳到下一个TAB位置)
|
009
|
\v
|
垂直制表(VT)
|
011
|
\\
|
代表一个反斜线字符''\'
|
092
|
\'
|
代表一个单引号(撇号)字符
|
039
|
\"
|
代表一个双引号字符
|
034
|
\0
|
空字符(NULL)
|
000
|
\ddd
|
1到3位八进制数所代表的任意字符
|
三位八进制
|
\xhh
|
1到2位十六进制所代表的任意字符
|
二位十六进制
|
#include
int main(void)
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf(" F C\n");
fahr = lower;
while(fahr <= upper)
{
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f %6.1f\n", fahr, celsius);
fahr = fahr + step;
}
return 0;
}
#include
int main(void)
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf("C F\n\n");
celsius = lower;
while(celsius <= upper)
{
fahr = (9.0/5.0) * celsius + 32.0;
printf("%3.0f %6.1f\n", celsius, fahr);
celsius = celsius + step;
}
return 0;
}
#include
/* print Fahrenheit-Celsius table */
int
main()
{
int fahr;
for (fahr = 300; fahr >= 0; fahr = fahr - 20)
printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
return 0;
}
方法:getchar()在没有输入符的时候,会返回EOF(end of file),如果getchar()==EOF,就说明没有输入了。我打印了一下EOF,发现是-1。EOF是定义在标准库
long 要占32位储存单元,%ld是打印long整型
C语言 单引号和双引号的区别 :单引号表示一个单个字符,而双引号是字符串。单引号中的字符实际上表示一个整型值,该整型值对应ASCII字符集中的字符常量。比如值65对应'A'字符常量。'\n'这个换行符对应值10.
nl=nw=nc=0;这样一句语句的赋值的实际过程是:nl=(nw=(nc=0));
/* This program prompts for input, and then captures a character
* from the keyboard. If EOF is signalled (typically through a
* control-D or control-Z character, though not necessarily),
* the program prints 0. Otherwise, it prints 1.
*
* If your input stream is buffered (and it probably is), then
* you will need to press the ENTER key before the program will
* respond.
*
* zy测试结果:
* 如果我点回车的话,会返回1,那么就是说明回车输入的不是EOF
* 但是当我输入control-D就回打印0,说明control-D会向服务器输出EOF
* control-Z没有输出
*/
#include
int main(void)
{
printf("Press a key. ENTER would be nice :-)\n\n");
printf("The expression getchar() != EOF evaluates to %d\n", getchar() != EOF);
return 0;
}
#include
int main(void)
{
printf("The value of EOF is %d\n\n", EOF);
return 0;
}
结果是-1
#include
int main(void)
{
int blanks, tabs, newlines;
int c;
int done = 0;
int lastchar = 0;
blanks = 0;
tabs = 0;
newlines = 0;
while(done == 0)
{
c = getchar();
if(c == ' ')
++blanks;
if(c == '\t')
++tabs;
if(c == '\n')
++newlines;
if(c == EOF)
{
if(lastchar != '\n')
{
++newlines; /* this is a bit of a semantic stretch, but it copes
* with implementations where a text file might not
* end with a newline. Thanks to Jim Stad for pointing
* this out.
*/
}
done = 1;
}
lastchar = c;
}
printf("Blanks: %d\nTabs: %d\nLines: %d\n", blanks, tabs, newlines);
return 0;
}
#include
int main(void)
{
int c;
int inspace;
inspace = 0;
while((c = getchar()) != EOF)
{
if(c == ' ')
{
if(inspace == 0)
{
inspace = 1;
putchar(c);
}
}
/* We haven't met 'else' yet, so we have to be a little clumsy */
if(c != ' ')
{
inspace = 0;
putchar(c);
}
}
return 0;
}
#include
int main()
{
int c, d;
while ( (c=getchar()) != EOF) {
d = 0;
if (c == '\\') {
putchar('\\');
putchar('\\');
d = 1;
}
if (c == '\t') {
putchar('\\');
putchar('t');
d = 1;
}
if (c == '\b') {
putchar('\\');
putchar('b');
d = 1;
}
if (d == 0)
putchar(c);
}
return 0;
}
#include
#define IN 1 //在一个单词内
#define OUT 0//在一个单词外
int main(void) {
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);//ctrl-d发送EOF,打印结果。
}
#include
int main(void)
{
int c;
int inspace;
inspace = 0;
while((c = getchar()) != EOF)
{
if(c == ' ' || c == '\t' || c == '\n')
{
if(inspace == 0)
{
inspace = 1;
putchar('\n');
}
/* else, don't print anything */
}
else
{
inspace = 0;
putchar(c);
}
}
return 0;
}
#include
#define MAXWORDLEN 10
int main(void)
{
int c;
int inspace = 0;//每遇见一个空格设置为1,每遇见一个字符设置为0
long lengtharr[MAXWORDLEN + 1];//以单词长度为下标的数组,>10的全部算作一个
int wordlen = 0;
int firstletter = 1;
long thisval = 0;//这一次长度
long maxval = 0;//单个单词的最大次数
int thisidx = 0;
int done = 0;
for(thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
{
lengtharr[thisidx] = 0;
}
while(done == 0)
{
c = getchar();
if(c == ' ' || c == '\t' || c == '\n' || c == EOF)
{
if(inspace == 0)
{
firstletter = 0;
inspace = 1;
if(wordlen <= MAXWORDLEN)
{
if(wordlen > 0)
{
thisval = ++lengtharr[wordlen - 1];
if(thisval > maxval)
{
maxval = thisval;//如果
}
}
}
else
{
thisval = ++lengtharr[MAXWORDLEN];
if(thisval > maxval)
{
maxval = thisval;
}
}
}
if(c == EOF)
{
done = 1;
}
}
else//不是空格,\t,\n,EOF,就是拿到了一个实在字符,单词长度加1
{
if(inspace == 1 || firstletter == 1)
{
wordlen = 0;
firstletter = 0;
inspace = 0;
}
++wordlen;
}
}
for(thisval = maxval; thisval > 0; thisval--)
{
printf("%4ld | ", thisval);
for(thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
{
if(lengtharr[thisidx] >= thisval)
{
printf("* ");
}
else
{
printf(" ");
}
}
printf("\n");
}
printf(" +");
for(thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
{
printf("---");
}
printf("\n ");
for(thisidx = 0; thisidx < MAXWORDLEN; thisidx++)
{
printf("%2d ", thisidx + 1);
}
printf(">%d\n", MAXWORDLEN);
return 0;
}
78 | *
77 | *
76 | *
75 | *
74 | *
73 | *
72 | *
71 | *
70 | *
69 | *
68 | *
67 | *
66 | *
65 | *
64 | *
63 | *
62 | *
61 | *
60 | *
59 | *
58 | *
57 | *
56 | *
55 | *
54 | *
53 | *
52 | *
51 | *
50 | *
49 | *
48 | *
47 | *
46 | *
45 | *
44 | *
43 | * *
42 | * *
41 | * *
40 | * *
39 | * *
38 | * *
37 | * *
36 | * *
35 | * *
34 | * *
33 | * *
32 | * *
31 | * * *
30 | * * *
29 | * * *
28 | * * *
27 | * * *
26 | * * *
25 | * * *
24 | * * *
23 | * * *
22 | * * *
21 | * * *
20 | * * *
19 | * * * *
18 | * * * *
17 | * * * * *
16 | * * * * *
15 | * * * * *
14 | * * * * * *
13 | * * * * * *
12 | * * * * * * *
11 | * * * * * * *
10 | * * * * * * *
9 | * * * * * * *
8 | * * * * * * *
7 | * * * * * * *
6 | * * * * * * *
5 | * * * * * * * *
4 | * * * * * * * * *
3 | * * * * * * * * * *
2 | * * * * * * * * * *
1 | * * * * * * * * * *
+---------------------------------
1 2 3 4 5 6 7 8 9 10 >10
Exercise 1-14. Write a program to print a histogram of the frequencies of different characters in its input.
#include
/* NUM_CHARS should really be CHAR_MAX but K&R haven't covered that at this stage in the book */
#define NUM_CHARS 256
int main(void)
{
int c;
long freqarr[NUM_CHARS + 1];
long thisval = 0;
long maxval = 0;
int thisidx = 0;
for(thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
{
freqarr[thisidx] = 0;
}
while((c = getchar()) != EOF)
{
if(c < NUM_CHARS)
{
thisval = ++freqarr[c];//字符的ASCII的值作为数组下标
if(thisval > maxval)
{
maxval = thisval;
}
}
else
{
thisval = ++freqarr[NUM_CHARS];
if(thisval > maxval)
{
maxval = thisval;
}
}
}
for(thisval = maxval; thisval > 0; thisval--)
{
printf("%4ld |", thisval);
for(thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
{
if(freqarr[thisidx] >= thisval)
{
printf("*");
}
else if(freqarr[thisidx] > 0)
{
printf(" ");
}
}
printf("\n");
}
printf(" +");
for(thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
{
if(freqarr[thisidx] > 0)
{
printf("-");
}
}
printf("\n ");
for(thisidx = 0; thisidx < NUM_CHARS; thisidx++)
{
if(freqarr[thisidx] > 0)
{
printf("%d", thisidx / 100);//打印百位
}
}
printf("\n ");
for(thisidx = 0; thisidx < NUM_CHARS; thisidx++)
{
if(freqarr[thisidx] > 0)
{
printf("%d", (thisidx - (100 * (thisidx / 100))) / 10 );//打印十位
}
}
printf("\n ");
for(thisidx = 0; thisidx < NUM_CHARS; thisidx++)
{
if(freqarr[thisidx] > 0)
{
printf("%d", thisidx - (10 * (thisidx / 10)));//打印个位
}
}
if(freqarr[NUM_CHARS] > 0)
{
printf(">%d\n", NUM_CHARS);
}
printf("\n");
return 0;
}
结果:
5 | *
4 | *
3 | * * * *
2 |** ** ** * *
1 |*******************
+-------------------
0000001111111111111
1334690000111111122
0296371459014567912
#include
float FtoC(float f)//这样的做法相当于把函数原型和函数定义写在一起了
{
float c;
c = (5.0 / 9.0) * (f - 32.0);
return c;
}
int main(void)
{
float fahr, celsius;
int lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf("F C\n\n");
fahr = lower;
while(fahr <= upper)
{
celsius = FtoC(fahr);
printf("%3.0f %6.1f\n", fahr, celsius);
fahr = fahr + step;
}
return 0;
}
C语言中被调用函数不能直接修改主调函数的值,而只能修改其私有的临时变量的值,说明其是值传递
如果想要函数修改主调函数的变量,那么调用这需要向被调用的函数提供带设置值的变量地址,也就是指针。
数组传递的是数组的起始位置的地址,所以,调用函数可以通过数组下标来访问和修改元素的值
字符串是用char数组来储存的,并却最后的常量的会以“\0”来表示结束。如"hello\n",的储存如下图所示:
#include
#define MAXLINE 1000 /* maximum input line size */
int getline1(char line[], int maxline);
void copy(char to[], char from[]);
/* print longest input line */
int main(void)
{
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 = getline1(line, MAXLINE)) > 0)
{
printf("%d: %s", len, line);
if(len > max)
{
max = len;
copy(longest, line);
}
}
if(max > 0)
{
printf("Longest is %d characters:\n%s", max, longest);
}
printf("\n");
return 0;
}
/* getline: read a line into s, return length */
int getline1(char s[], int lim)
{
int c, i, j;
for(i = 0, j = 0; (c = getchar())!=EOF && c != '\n'; ++i)
{
if(i < lim - 1)
{
s[j++] = c;
}
}
if(c == '\n')
{
if(i <= lim - 1)
{
s[j++] = c;
}
++i;
}
s[j] = '\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;
}
}
由于发生下列错误,我将getline()改为了getline1。
test.c:37:5: error: conflicting types for ‘getline’
/usr/include/stdio.h:675:20: note: previous declaration of ‘getline’ was here
#include
#define MINLENGTH 81
int readbuff(char *buffer) {
size_t i=0;
int c;
while (i < MINLENGTH) {
c = getchar();
if (c == EOF) return -1;
if (c == '\n') return 0;
buffer[i++] = c;
}
return 1;
}
void copyline(char *buffer) {
size_t i;
int c;
for(i=0; i
注意:
#include
#include
#define MAXQUEUE 1001
int advance(int pointer)
{
if (pointer < MAXQUEUE - 1)
return pointer + 1;
else
return 0;
}
int main(void)
{
char blank[MAXQUEUE];//用于存储制表符或者是空格。
int head, tail;
int nonspace;
int retval;
int c;
retval = nonspace = head = tail = 0;
while ((c = getchar()) != EOF) {
if (c == '\n') {
head = tail = 0;
if (nonspace)
putchar('\n');
nonspace = 0;
}
else if (c == ' ' || c == '\t') {
if (advance(head) == tail) {//这里只是用head判断一下,并没实际让head+1
putchar(blank[tail]);
tail = advance(tail);
nonspace = 1;
retval = EXIT_FAILURE;
}
blank[head] = c;//将这个是 空格或者是\t存了起来
head = advance(head);//这里是让head+1
}
else {
while (head != tail) {
putchar(blank[tail]);
tail = advance(tail);
}
putchar(c);
nonspace = 1;
}
}
return retval;
}
刚开始比较难懂。但是举个例子按着逻辑一点一点的走,还是比较好懂。
#include
#define MAX_LINE 1024
void discardnewline(char s[])
{
int i;
for(i = 0; s[i] != '\0'; i++)//注意getline里面把这里
{
if(s[i] == '\n')
s[i] = '\0';
}
}
int reverse(char s[])
{
char ch;
int i, j;
for(j = 0; s[j] != '\0'; j++)
{
}
--j;
for(i = 0; i < j; i++)
{
ch = s[i];
s[i] = s[j];
s[j] = ch;
--j;
}
return 0;
}
int getline1(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;//这些++的顺序都很微妙,因为在for语句之中已经++过了
}
s[i] = '\0';//末尾加的这个discardnewline()函数有影响。
return i;
}
int main(void)
{
char line[MAX_LINE];
while(getline1(line, sizeof line) > 0)
{
discardnewline(line);
reverse(line);
printf("%s\n", line);
}
return 0;
}
不同函数内,声明的变量是局部变量,函数执行完毕后会消失,对应的是外部变量(全局变量)。
外部变量一直存在,不会因为函数的调用而产生。函数对外部变量的值的改变也会影响。
全局变量的使用可以使用extern关键字来显式声明,在同一份文件下,这种声明可以省略,但是如果变量在file1里面声明,却在file2里面使用,那么必须使用extern关键字来声明。习惯会把变量和函数的extern声明放在头文件中,再包含头文件。
定义(define)是指,分配内存。外部变量定义在所有函数外,可以声明于函数内,声明只是说明函数性质。
不要频繁使用外部变量原因有2: 外部变量会在不知道的情况下被修改;函数会失去通用性。业就是,不能把函数
#include
#include
#include
#define MAX_BUFFER 1024
#define SPACE ' '
#define TAB '\t'
int CalculateNumberOfSpaces(int Offset, int TabSize)
{
return TabSize - (Offset % TabSize);
}
/* K&R's getline() function from p29 */
int getline1(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;
}
int main(void)
{
char Buffer[MAX_BUFFER];
int TabSize = 5; /* A good test value */
int i, j, k, l;
while(getline1(Buffer, MAX_BUFFER) > 0)
{
for(i = 0, l = 0; Buffer[i] != '\0'; i++)
{
if(Buffer[i] == TAB)
{
j = CalculateNumberOfSpaces(l, TabSize);
for(k = 0; k < j; k++)
{
putchar(SPACE);
l++;
}
}
else
{
putchar(Buffer[i]);
l++;
}
}
}
return 0;
}
很奇怪,我看懂了代码,我感觉带代码和题干不一样。题干中有一句:to the next tab stop(使空格充满到下一个制表符终止的位置),我始终没想通。看了代码,觉得代码也做了一些特别的处理。
/******************************************************
KnR 1-21
--------
Write a program "entab" which replaces strings of
blanks with the minimum number of tabs and blanks
to achieve the same spacing.
Author: Rick Dearman
email: [email protected]
******************************************************/
#include
#define MAXLINE 1000 /* max input line size */
#define TAB2SPACE 4 /* 4 spaces to a tab */
char line[MAXLINE]; /*current input line*/
int getline1(void); /* taken from the KnR book. */
int
main()
{
int i,t;
int spacecount,len;
while (( len = getline1()) > 0 )
{
spacecount = 0;
for( i=0; i < len; i++)
{
if(line[i] == ' ')
spacecount++; /* increment counter for each space */
if(line[i] != ' ')
spacecount = 0; /* reset counter */
if(spacecount == TAB2SPACE) /* Now we have enough spaces
** to replace them with a tab
*/
{
/* Because we are removing 4 spaces and
** replacing them with 1 tab we move back
** three chars and replace the ' ' with a \t
*/
i -= 3; /* same as "i = i - 3" */
len -= 3;
line[i] = '\t';
/* Now move all the char's to the right into the
** places we have removed.
** 因为用了一个'\t'替换调用了一个4个空格,还剩于三个,所以,我们需要把元素从右往左移
*/
for(t=i+1;t
关于问题的答案,我认为是制表符。
/******************************************************
KnR 1-22
--------
Write a program that wraps very long lines of input
into two or more shorter lines.
Author: Rick Dearman
email: [email protected]
******************************************************/
#include
#define MAXLINE 1000 /* max input line size */
char line[MAXLINE]; /*current input line*/
int getline1(void); /* taken from the KnR book. */
int
main()
{
int t,len;
int location,spaceholder;
const int FOLDLENGTH=70; /* The max length of a line */
while (( len = getline1()) > 0 )
{
if( len < FOLDLENGTH )
{
}
else
{
/* if this is an extra long line then we
** loop through it replacing a space nearest
** to the foldarea with a newline.
*/
t = 0;
location = 0;
while(t
/* Lew Pitcher */
/*/
** derem - remove C comments
**
** (attempt to solve K&R Exercise 1-22)
**
** As I only have v1 copy of K&R, I cannot
** be sure what is covered in K&R ANSI chapter 1.
** So, I restrict myself to the components covered
** in K&R v1 chapter 1, but modified for requisite ANSI
** features (int main() and return value).
**
** Components covered in v1 K&R chapter 1 include:
** while (), for (), if () else
** getchar(), putchar(), EOF
** character constants, character escapes
** strings
** array subscripting
**
** Not directly covered are
** string subscripting ( "/*"[0] )
** initializers ( int state = PROGRAM; )
**/
/*/*/
#include
#define PROGRAM 0
#define BEGIN_COMMENT 1
#define COMMENT 2
#define END_COMMENT 3
#define QUOTE 4
int main(void)
{
int this_char, quote_char;
int state;
state = PROGRAM;
while ((this_char = getchar()) != EOF)
{
if (state == PROGRAM)
{
if (this_char == '/')
state = BEGIN_COMMENT;
else if ((this_char == '"') || (this_char == '\''))
{
state = QUOTE;//引号状态的出现是因为在引号了输入什么都不会是注释
putchar(quote_char = this_char);
}
else putchar(this_char);
}
else if (state == BEGIN_COMMENT)
{
if (this_char == '*')
state = COMMENT;
else
{
putchar('/'); /* for the '/' of the comment 如果我把这句删掉,就也能可以将//的注释删掉,但是我不知道为什么作业要这样做。*/
if (this_char != '/')
{
state = PROGRAM;
putchar(this_char);
}
else state = COMMENT; /* stuttered */
}
}
else if (state == QUOTE)
{
putchar(this_char);
if (this_char == '\\')//因为只有在引号里面才会出现转义字符撒
putchar(getchar()); /* escaped character */
else if (this_char == quote_char)
state = PROGRAM;
}
else if (state == COMMENT)
{
if (this_char == '*')
state = END_COMMENT;
}
else if (state == END_COMMENT)
{
if (this_char == '/')
state = PROGRAM;
else if (this_char != '*') /* stuttered */
state = COMMENT;
}
}
return 0;
}
/******************************************************
KnR 1-24
--------
Write a program to check the syntax of a C program
for matching {} () "" '' []
Author: Rick Dearman
email: [email protected]
******************************************************/
#include
#define MAXLINE 1000 /* max input line size */
char line[MAXLINE]; /*current input line*/
int getline1(void); /* taken from the KnR book. */
int
main()
{
int len=0;
int t=0;
int brace=0, bracket=0, parenthesis=0;
int s_quote=1, d_quote=1;//单引号和双引号是的匹配是:“”,‘’这样的,所以必须使用这种方式
while ((len = getline1()) > 0 )
{
t=0;
while(t < len)
{
if( line[t] == '[')
{
brace++;
}
if( line[t] == ']')
{
brace--;
}
if( line[t] == '(')
{
parenthesis++;
}
if( line[t] == ')')
{
parenthesis--;
}
if( line[t] == '\'')
{
s_quote *= -1;
}
if( line[t] == '"')
{
d_quote *= -1;
}
t++;
}
}
if(d_quote !=1)
printf ("Mismatching double quote mark\n");
if(s_quote !=1)
printf ("Mismatching single quote mark\n");
if(parenthesis != 0)
printf ("Mismatching parenthesis\n");
if(brace != 0)
printf ("Mismatching brace mark\n");
if(bracket != 0)
printf ("Mismatching bracket mark\n");
if( bracket==0 && brace==0 && parenthesis==0 && s_quote == 1 && d_quote == 1)
printf ("Syntax appears to be correct.\n");
return 0;
}
/* getline: specialized version */
int getline1(void)
{
int c, i;
extern char line[];
for ( i=0;i
这是一个简单的版本,因为它不能应付这样的情况:
[)](
Syntax appears to be correct.
更多,请参考: Answer to Exercise 1-24, page 34