《C Primer Plus》笔记.docx
《《C Primer Plus》笔记.docx》由会员分享,可在线阅读,更多相关《《C Primer Plus》笔记.docx(107页珍藏版)》请在冰豆网上搜索。
《CPrimerPlus》笔记
CPrimerPlus笔记
By:
riusksk(泉哥)
Blog:
1.scanf()在读取输入时会自动将空字符’\0’插入字符串末尾,而且当它遇到第一个空白字符空格(blank)、制表符(tab)或者换行符(newline)时会停止读取,因此使用%s的scnaf()只会把一个单词而不是把整个语句作为字符串读入,此时我们一般用gets()来处理一般的字符串。
2.字符串常量”x”与字符常量’x’不同,’x’属于基本类型(char),而”x”则属于派生类型(char数组),另外,”x”实际上是由两个字符(’x’和空字符’\0’)组成的。
3.strlen()是以字符为单位给出字符串的长度,其中空字符’\0’并不计算在内,而sizeof()是以字节为单位给出数据的大小,其中还包括空字符’\0’。
4.定义符号常量的意义:
a.提供更多的信息,增强代码的可读性;b.便于更改代码,特别对于在多处使用同一常量而又必须改变它的值时更为适用。
可将符号常量名定义为大写字母,当遇到大写的符号名时,就可知道它是一个常量而变量了,比如:
#definePI3.14159
这里如果我们这样定义:
floatpi=3.14159;
由于pi是个变量,程序可能意外地改变它的值,因此我们使用#define来定义它。
除了以上方法之外,我们还可以使用const修饰符来创建符号常量,此时它就成为只读值,在计算中是不可改变的,比如:
constfloatpi=3.14159;
5.linits.h:
整数限制头文件,float.h:
浮点数限制头文件。
例如:
#include
#include
#include
intmain(void)
{
printf("Maxintvalueonthissystem:
%d\n",INT_MAX);
printf("Minintvalueonthissystem:
%d\n",INT_MIN);
printf("Maxfloatnormalvalueonthissystem:
%e\n",FLT_MAX);
printf("Minfloatnormalvalueonthissystem:
%e\n",FLT_MIN);
return0;
}
输出结果:
Maxintvalueonthissystem:
2147483647
Minintvalueonthissystem:
-2147483648
Maxfloatnormalvalueonthissystem:
3.402823e+038
Minfloatnormalvalueonthissystem:
1.175494e-038
6.不匹配的浮点转换实例:
n1在堆栈中占用8字节(float被转换成double),n2占用8字节,而n3和n4则分别占用4字节,prinft()在读取堆栈中的值时,它是根据转换说明符去读取的。
%ld说明符指出,printf()应该读取4个字节,所以printf()在堆栈中读取前4个字节作为它的第一个值,即n1的前半部分,它被解释成一个长整数(longinteger)。
下一个%ld说明符再读取4字节,即n1的后半部分,它被解释成第二个长整数(longinteger)。
同样,%ld的第三、四个实例使得n2的前半部分和后半部分被读出,并被解释成两个长整数(longinteger)。
7.printf()返回所打印的字符的数目,如果输出错误,则返回一个负数(旧版本的printf会有不同的返回值),比如:
#include
intmain(void)
{
inttest=123;
intretvalue;
retvalue=printf(“thetestvalueis%d\n”,test);
printf(“Theprintf()functionprinted%dcharacters.\n”,retvalue);
return0;
}
输出结果:
thetestvalueis123
Theprintf()functionprinted22characters.
8.在scanf()格式字符串的说明符中,除了%c以外,其它说明符均会自动跳过输入项之前的空格。
比如:
#include
intmain(void)
{
inta;
printf("enter:
\n");
scanf("%d",&a);
printf("%d.\n",a);
return0;
}
输出结果:
enter:
3
3.
这里并没有输出空格。
又比如:
#include
intmain(void)
{
chara;
printf("enter:
\n");
scanf("%c",&a);
printf("%c.\n",a);
return0;
}
输出结果:
enter:
a
.
这里就是输出空格了。
9.scanf()函数返回成功读入的项目的个数,如果它没有读取任何项目(当它期望一个数字而你又键入一个非数字字符串时就会发生这种情况),scnaf()会返回值0。
当它检测到“文件结尾”时,它返回EOF(stdio.h中将EOF定义为值-1)。
10.printf()和scanf()的*修饰符:
代码一:
//----使用可变宽度的输出字段----
#include
intmain(void)
{
unsignedwidth,precision;
intnumber=256;
doubleweight=242.5;
printf("Whatfieldwidth?
\n");
scanf("%d",&width);
printf("Thenumberis:
%*d:
\n",width,number);
printf("Nowenterawidthandaprecision:
\n");
scanf("%d%d",&width,&precision);
printf("Weight=%*.*f\n",width,precision,weight);
printf("Done!
\n");
return0;
}
变量width提供字段宽度,而number就是要打印的数字。
其运行结果:
Whatfieldwidth?
3
Thenumberis:
256:
Nowenterawidthandaprecision:
37
Weight=242.5000000
Done!
代码二:
/*跳过输入的头两个整数,此功能可用于读取一个文件中某个特定的列*/
#include
intmain(void)
{
intn;
printf("pleaseenterthreeintegers:
\n");
scanf("%*d%*d%d",&n);
printf("thelastintegerwas%d\n",n);
return0;
}
输出结果:
pleaseenterthreeintegers:
111222333
thelastintegerwas333
11.取模运算符%只用于整数运算,对于浮点数使用该运算符将是无效的。
12.前缀增量与后缀增量的区别:
先看下面的代码:
#include
intmain(void)
{
inta=1,b=1;
intaplus,plusb;
aplus=a++;/*后缀*/
plusb=++b;/*前缀*/
printf("aaplusbplusb\n");
printf("%1d%5d%5d%5d\n",a,aplus,b,plusb);
return0;
}
运行结果:
aaplusbplusb
2122
显然,a和b都加一了,但aplus是a改变之前的值,而plusb却是b改变之后的值。
再比如,q=2*++a;它会先将a+1,然后再2*a;而q=2*a++却是先2*a,再将积加1。
再举个例子:
b=++i//如果使用i++,b会有不同结果,而如果使用下列语句来代替它:
++i;//第1行
b=i;//如果在第1行使用了i++,b的结果仍会是相同的。
13.增量运算符++与减量运算符--具有很高的结合优先级,只有圆括号比它们的优先级高。
所以x*y++相当于(x)*(y++)。
14.在y=(4+x++)+(6+x++);中表达式(4+x++)不是一个完整的表达式,所以C不能保证在计算子表达式4+x++后立即增加x。
这里,完整表达式是整个赋值语句,并且分号标记了顺序点,所以C能保证的是在程序进入后续语句前x将被增加两次。
C没有指明x是在每个子表达式被计算后增加还是在整个表达式被计算后增加,这就是我们要避免使用这类语句的原因。
15.请看以下代码:
#include
intmain(void)
{
inti=1;
floatn;
while(i++<5)
{
n=(float)1/i;//n=1.0/i;如果写成1/i,则当i>1时,n都会等于0
printf("%f\n",n);
}
return0;
}
16.请看代码:
#include
#defineFORMAT"%s!
Ciscool!
\n"
intmain(void)
{
intnum=10;
printf(FORMAT,FORMAT);
printf("%d\n",++num);
printf("%d\n",num++);
printf("%d\n",num--);
printf("%d\n",num);
return0;
}
运行结果:
%s!
Ciscool!
!
Ciscool!
11
11
12
11
17.while循环语句在遇到第一个分号之后就退出循环,例如以下代码:
#include
intmain(void)
{
intn=0;
while(n++<3);/*line7*/
printf("nis%d\n",n);/*line8*/
printf("That'sallthisprogramdoes.\n");
return0;
}
输出结果:
nis4
That'sallthisprogramdoes.
由于while(n++<3);之后存在分号,因此它只是循环的执行n++,直至它小于3才退出循环,相当于一个空语句,退出循环时n刚好等于4。
有时,程序员有意地使用带有空语句的while语句,因为所有的工作都在判断语句中进行。
例如,你想要跳过输入直到第一个不为空格或数字的字符,可以使用这样的循环:
while(scanf(“%d”,&num)==1)
;/*跳过整数输入*/
只要输入一个整数,则scanf()就返回1,循环就会继续。
18.math.h头文件中声明的fabs()函数用于返回一个浮点值的绝对值,即没有代数符号的值。
19.请看代码:
#include
intmain(void)
{
intnum=0;
for(printf("keepenteringnumbers!
\n");num!
=6;)
scanf("%d",&num);
printf("that'stheoneIwant!
\n");
return0;
}
输出结果:
keepenteringnumbers!
1
2
3
4
5
6
that'stheoneIwant!
20.houseprice=249,500;相当于:
houseprice=249;
500;
而houseprice=(249,500);相当于houseprice=500;
21.求S=1+1/2+1/4+1/8+1/16+……
#include
intmain(void)
{
intt_ct;
doubletime,x;
intlimit;
printf("enterthenumberoftermsyouwant:
");
scanf("%d",&limit);
for(time=0,t_ct=1,x=1;t_ct<=limit;t_ct++,x*=2.0)
{
time+=1.0/x;
printf("time=%fwhenterms=%d.\n",time,t_ct);
}
return0;
}
运行结果:
enterthenumberoftermsyouwant:
15
time=1.000000whenterms=1.
time=1.500000whenterms=2.
time=1.750000whenterms=3.
time=1.875000whenterms=4.
time=1.937500whenterms=5.
time=1.968750whenterms=6.
time=1.984375whenterms=7.
time=1.992188whenterms=8.
time=1.996094whenterms=9.
time=1.998047whenterms=10.
time=1.999023whenterms=11.
time=1.999512whenterms=12.
time=1.999756whenterms=13.
time=1.999878whenterms=14.
time=1.999939whenterms=15.
22.代码:
#include
intmain(void)
{
intk;
for(k=1,printf(“%d:
Hi!
\n”,k);printf(“k=%d\n”,k),
k*k<26;k+=2,printf(“Nowkis%d\n”,k))
printf(“kis%dintheloop\n”,k);
return0;
}
运行结果:
1:
Hi!
k=1
kis1intheloop
Nowkis3
k=3
kis3intheloop
Nowkis5
kis5intheloop
Nowkis7
k=7
23.让程序要求用户输入一个大写字母,使用嵌套循环产生像下面这样的金字塔图案,比如输入E:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
提示:
使用一个外部循环来处理行,在每一行中使用三个内部循环,一个处理空格,一个以升序打印字母,一个以降序打印字母。
源码如下:
#include
intmain(void)
{
inta;
chari,j,k;
printf("请输入字母:
");
scanf("%c",&i);/*输入的字母用i*/
for(k='A';k<=i;k++)/*输入的字母i減掉A的数目就是要做的行数*/
{
for(a=(i-k);a>0;a--)
printf("");/*印出空白字元*/
for(j='A';j<=k;j++)
printf("%c",j);/*递增印出字母*/
for(j=k-1;j>='A';j--)
printf("%c",j);/*递減印出字母*/
printf("\n");
}
return0;
}
24.getchar()没有参数,它返回来自输入设备的下一个字符,比如:
ch=getchar();相当于scanf(%c,&ch);
putchar()打印出它的参数,比如putchar(ch);相当于printf(“%c”,ch);
这两个函数通常在stdio.h文件中定义,而且通常只是个预处理宏,而不是真正的函数。
25.ctype.h系列字符函数:
ctype.h头文件包含了一些函数的原型,这些函数接受一个字符作为参数,如果该字符属于某特定的种类则返回真,否则返回假,比如isalpha()函数判断是否为字母。
一些映射函数,比如转换为小写字母tolower()函数,它并不改变原始的参数,它们只返回改变后的值,也就是说,tolower(ch);//对ch没有影响,若要改变ch,可以这样做:
ch=tolower(ch);。
26.
27.求2到num之间的所有数,看它们是否可以整除num,比如求144的约数,由于一次成功的num%div测试可以得到两个约数,拿144除以2,可以得到72,则这两个数均为其约数,这样,我们可以将测试的数缩小到num的平方根即可,而不必到num。
如果测试的数是一个完全平方数,就只需打印出一个数。
如果测试的数是一个素数,那么程序流程也进不了if语句中,对此我们可设置一个布尔值变量,即标志(flag):
#include
#include//BOOL,TRUE,FALSE包含在windows.h头文件中
intmain(void)
{
unsignedlongnum;
unsignedlongdiv;
BOOLisPrime;
printf("Pleaseenteranintegerforanalysis,enterqtoquit.\n");
while(scanf("%lu",&num)==1)
{
for(div=2,isPrime=TRUE;(div*div)<=num;div++)
{
if(num%div==0)
{
if((div*div)!
=num)
printf("%luisdivisibleby%luand%lu.\n",
num,div,num/div);
else
printf("%luisdivisibleby%lu.\n",
num,div);
isPrime=FALSE;
}
}
if(isPrime&&num!
=1)//因为1不进入以上循环,而isPrime被初始化为真,以致其直接执行以下语句,因此要排除num=1的情况。
printf("%luisprime.\n",num);
printf("Pleaseenteranotherintegerforanalysis,enterqtoquit.\n");
}
printf("Bye!
\n");
return0;
}
执行结果:
Pleaseenteranintegerforanalysis,enterqtoquit.
144
144isdivisibleby2and72.
144isdivisibleby3and48.
144isdivisibleby4and36.
144isdivisibleby6and24.
144isdivisibleby8and18.
144isdivisibleby9and16.
144isdivisibleby12.
Pleaseenteranotherintegerforanalysis,enterqtoquit.
1
Pleaseenteranotherintegerforanalysis,enterqtoquit.
q
Bye!
28.逻辑运算符:
(练习&&时间)==完美
29.由于世界各地,并不是所有的键盘都有与美式键盘相同的符号。
因此,C99标准为逻辑运算符增加了可选择的拼写法,它们在iso646.h头文件中定义。
如果包含了这个头文件,那么就可以用and代替&&,用or代替||,用not代替!
。
30.!
运算符的优先级仅次于圆括号,&&运算符的优先级高于||,这二者的优先级都低于关系运算符而高于赋值运算,即()>!
>&&>||,对于逻辑表达式是从左至右求值的。
31.在定义测试范围时,请勿效仿数学上常用的写法:
if(90<=range<=100)//语义错误
printf(“Goodshow!
\n”);
问题在于该代码存在语义错误,而不是语法错误,所以编译器并不会捕获它(尽管可能会发出警告)。
因为对<=运算符的求值顺序是由左到右的,所以它会被解释成:
(90<=range)<=100
子表达式90<=range的值为1或0,无论是其中任何一个值,它都将小于100因此不管range的值是什么,整个表达式总为真,所以需要使用&&来检查范围》
if(range>=90&&range<=100)
printf(“Goodshow!
\n”);
32.大量现有代码利用范围测试来检测一个字符是不是(比方说)小写字母。
例如,假设ch是个char变量:
if(ch>=‘a’&&ch<=‘z’)
printf(“That’salowercasecharacter.\n”);
对于ASCII那样的字符编码可以工作,因为在这种编码中连续字母的编码是相邻的数值。
然而,对于包括EBCDIC在内的一些编码就不正确了。
进行这种测试的移植性最好的方法是使用ctype.h系列中的islower()函数:
if(islower(ch))
printf(“That’salowercasecharacter.\n”);
33.计算给定的平方英尺的面积涂油漆,全部涂完需要多少罐油漆。