在学完整本书之后,开始重头再复习难题,第一部分,先把课后的复习题中的重难题记录下来,做个笔记,以后每天要坚持写一到两个小时代码。
第八章
C的标准I/O库把不同的文件映射为统一的流来统一处理。
第9章第9题
给定下面的输出:
Please choose one of the following:
1)copy files 2)move files
3)remove files 4)quit
Enter the number of your choice:
a.编写一个函数,显示一份有4个选项的菜单,提示用户进行选择(输出如上所示)。
b.编写一个函数,接受两个Int 类型的参数分别显示上限和下限。该函数从用户的输入中读取整数。如果整数超出规定的上下限,函数再次打印菜单(使用a部分的函数)提示用户输入,然后获取一个新值。如果用户输入的整数在规定范围内,该函数则把该整数返回主调函数,如果用户输入一个非整数字符,该函数应返回4.
c.使用本题a和b部分的函数编写一个最小型的程序。最小型的意思是,该程序不需要实现菜单中各选项的功能,只需显示这些选项并获取有效的响应即可。
答案:
下面是一个最小的程序,showmenu()和getchoice()函数分别是A和B的答案。
#include<stdio.h>
void showmenu();
int getchoice(int,int):
int main()
{
int res;
showmenu();
while((res=getchoice(1,4)!=4)
{
printf("I like choice %d.\n",res);
showmenu();
}
printf("Bye!\n");
return 0;
}
void showmenu()
{
printf("Please choose one of the following:\n");
printf("1)copy files 2)move files\n");
printf("3)remove files 4)quit\n");
printf("Enter the number of your choice:\n);
}
int getchoice(int low,int high)
{
int ans;
int good;
good=scanf("%d",&ans);
while(good==1&&(ans<low||ans>high))
{
printf("%d is not a valid choice;try again\n",ans);
showmenu();
scanf("%d",&ans);
}
if(good!=1)
{
printf("Non-numeric input.");
ans=4;
}
return ans;
}
内容注释
在两个!之间有一个空字符,但是通常该字符不会产生任何打印的效果
*--pc的意思是把指针减1,并使用储存在该位置上的值,--*pc的意思是解引用pc指向的值,然后把该值减1(例如,H变成G)。
第11章第8题
#include<stdio.h>
int main()
{
char str1[]="gawsie";
char str2[]="bletonism";
char *ps;
int i=0;
for(ps=str1;*ps!='\0';ps++)
{
if(*ps=='a'||*ps=='e')
putchar(*ps);
else
(*ps)--;
}
putchar('\n');
while(str2[i]!='\0')
{
printf("%c",i%3?str2[i]:'*');
++i;
}
return 0;
}
11题:
本章定义的s_gets()函数,可以用strchr()函数代替其中的while循环来查找换行符。请改写该函数
#include<stdio.h>
#include<string.h>
char*s_gets(char*st,int n)
{
char*ret_val;
char*find;
ret_val=fgets(st,b,stdin);
if(ret_val)
{
find=strchr(st,'\n');
if(find)
*find='\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;
}
第12题 设计一个函数,接受一个指向字符串的指针,返回指向该字符串第1个空格字符的指针,或如果未找到空格字符,则返回空指针。
①法:#include<stdio.h>
char*strblk(char*string)
{
while(*string !=' '&&*string !='\0')
string++;
if(*string=='\0')
return NULL;
else
return string;
}
②法可以防止函数修改字符串,但是允许使用返回值改变字符串。表达式(char*)string被称为“通过强制类型转换取消const"
#include<stdio.h>
char*strblk(const char*string)
{
while(*string !=‘ ’&&*string!='\0')
string++;
if(*string=='\0')
return NULL;
else
return(char*)string;
}
自动存储类别;寄存器存储类别;静态、无链接存储类别是可以成为它所在函数的局部变量。、
静态、无链接存储类别;静态、内部链接存储类别;静态、外部链接存储类别是在它所在程序的运行期一直存在
静态、外部链接存储类别可以被多个文件使用。静态、内部链接存储类别只能在一个文件中使用
关键字extern用于声明中,表明该变量或函数已定义在别处
第12章第8题:
#include<stdio.h>
char color='B';
void first(void);
void second(void);
int main(void)
{
extern char color;
printf("color in main() is %c\n",color);
first();
printf("color in main() is %c\n",color);
second();
printf("color in main() is %c\n",color);
return 0;
}
void first(void)
{
char color;
color ='R';
printf("color in first() is %c\n",color);
}
void second()
{
color ='G';
printf("color in second() is %c\n",color);
}
得出结论:
color in main() is B
color in first() is R
color in main() is B
color in second() is G
color in main() is G
第13章第4题:
编写一个程序,不接受任何命令行参数或接受一个命令行参数,如果有一个参数,将其解释为文件名,如果没有参数,使用标准输入(stdin)作为输入,假设输入完全是浮点数,该程序要计算和报告输入数字的算术平均值。
答:#include<stdio.h>
#include<stdlib.h>
int main(int argc,char*argv[ ])
{
FILE*fp;
double n;
double sum=0.0;
int ct=0;
if(argc==1)
fp=stdin;
else if(argc==2)
{
if((fp=fopen(argv[1],"r"))==NULL)
{
fprintf(stderr,"Can't open %s\n",argv[1]);
exit(EXIT_FAILURE);
}
}
else
{
fprintf(stderr,"Usage:%s [filename]\n",argv[0]);
exit(EXIT_FAILURE);
}
while(fscanf(fp,"%lf",&n)==1)
{
sum+=n;
++ct;
}
if(ct>0)
printf("Average of %d values=%f\n",ct,sum/ct);
else
printf("No valid data.\n");
return 0;
}
第13章第5题
编写一个程序,接受两个命令行参数,第一个参数是字符,第二个参数是文件名。要求该程序只打印文件中包含给定字符的那些行。
答:
#include<stdio.h>
#include<stdlib.h>
#define BUF 256
int has_ch(char ch,const char*line);
int main(int argc,char*argv[ ])
{
FILE*fp;
char ch;
char line [BUF];
if(argc !=3)
{
printf("Usage:%s character filename\n",argv[0]);
exit (EXIT_FAILURE);
}
while(fgets(line,BUF,fp)!=NULL)
{
if(has_ch(ch,line))
fputs(line,stdout);
}
fclose(fp);
return 0;
}
int has_ch(char ch,const char*line)
{
while(*line)
if(ch==*line++)
return 0;
}
fgets()和fputs()函数要一起使用,因为fgets()会把按下Enter键的\n留在字符串中,fputs()与puts()不一样,不会添加一个换行符。
二进制文件与文本文件的区别是,这两种文件格式对系统的依赖性不同,二进制和文本流的区别包括是在读写流时程序执行的转换(二进制流不转换,而文本流可能要转换换行符和其他字符)
a+只允许在文件的末尾添加内容,w+模式提供一个空文件,丢弃文件原来的内容,r+适合用来更改文件中已有的内容。
第14章第10题
假设有如下结构:
struct gas
{float distance;
float gals;
float mpg;
};
a 设计一个函数,接受struct gas 类型的参数,假设传入的结构包含distance和gals信息,该函数为mpg成员计算正确的值,并把值返回该结构
b设计一个函数,接受struct gas 类型的参数,假设传入的结构包含distance和gals信息,该函数为mpg成员计算正确的值,并把值赋给合适的成员。
答:
struct gas
{float distance;
float gals;
float mpg;
};
struct gas mpgs(struct gas trip)
{
if(trip.gals>0)
trip.mpg=trip.distance/trip.gals;
else
trip.mpg=-1.0;
return trip;
}
void set_mpgs(struct gas*ptrip)
{
if(ptrip->gals>0)
ptrip->mpg=ptrip->distance/ptrip->gals;
else
ptrip->mpg=-1.0;
}
注意,第一个函数不能直接改变其主调程序中的值,所以必须用返回值才能传递信息。
struct gas idaho={430.0,14.8};//设置前两个成员
idaho=mpgs(idaho); //重置数据结构
但是,第2个函数可以直接访问最初的结构;
struct gas ohio={583,17.6} //设置前两个成员
set_mpgs(&ohio); //设置第3个成员
声明一个标记为choices的枚举,把枚举常量No,yes 和Maybe分别设置为0、1、2
enum choices{no,yes,maybe};
把下面的十进制转换为二进制
3 00000011
13 00001101
59 00111011
119 01110111
把下面二进制转换为十进制,八进制和十六进制
00010101 21, 025 0x15
01010101 85 0125 0x55
01001100 76 0114 0x4C
10011101 157 0235 0x9D
第16章第13题
假设datal是内含100个double类型元素的数组,data2是内含300个double类型元素的数组
a编写memcpy()的函数调用,用data2中的前100个元素拷贝到datal中
b编写memcpy()的函数调用,用data2中的后100个元素拷贝到datal中
答
a qsort((void*)scores,(size_t)1000,sizeof(double),comp);
b 下面是一个比较使用的比较函数:
int comp(const void*p1,const void*p2)
{
const int*a1=(const int*)p1;
const int*a2=(const int*)p2;
if(*a1>*a2)
return -1;
else if(*a1==*a2)
return 0;
else
return 1;
}