复习:
1、输出缓冲区
满足哪些条件会刷新输出缓冲区
1、遇到'\n'
2、遇到输入语句
3、缓冲区满4k
4、程序正常结束
5、fflush(stdout)
2、输入缓冲区
1、想要输入的是整形、浮点型,但缓冲区中字符型,此时读取会失败,并且继续残留在缓冲区中影响后面的输入
解决:根据scanf返回值判断是否成功,失败的话清空输入缓冲区并且重新输入
stdin->_IO_read_ptr=stdin->_IO_read_end;
2、使用fgets是,如果输入的字符超过size-1时,超出部分会残留在输入缓冲区中,会影响接下来的输入
解决:判断字符串的最后一个字符是否是'\n',如果不是说明缓冲区中有残留
scanf("%*[^\n]");
scanf("%*c");
或者直接
stdin->_IO_read_ptr=stdin->_IO_read_end;(只限Linux)
3、先输入整型或浮点型,再输入字符或字符串时,前一次可能会残留一个'\n',会影响后面字符或者字符串的输入
字符:
scanf(" %c",&ch);
字符串:
//scanf("%d ",&num);
scanf("%*c");
gets(str);
3、常考的字符串处理函数
strlen\strcpy\strcat\strcmp
memcpy\memmove\memset\memcmp(按字节比)
4、sprintf\sscanf
sprintf:把各种类型数据转换成字符串
sccanf:把字符串中解析各种类型的数据到变量中
----------------------------------------
通讯录项目(初步):
姓名、性别、电话,最多存储50个联系人
功能:
1、添加新联系人
2、按名字删除联系人
3、按名字修改联系人
4、查找联系人,名字或电话,支持模糊查询
5、显示所有人联系人信息
6、退出系统
方法一:
#include <stdio.h>
#include <string.h>
static char Name[51][20]={};
static char Num[51][12]={};
static char Sex[51][2]={};
int order=0;
void add(void);
void delete(void);
void revise(void);
void seek(void);
void show_view(void);
void show(void);
int main(int argc,const char* argv[])
{
int i;
for(;;)
{
show_view();
scanf("%d",&i);
printf("\n");
//stdin->_IO_read_ptr=stdin->_IO_read_end;
switch(i)
{
case 1: add();break;
case 2: delete();break;
case 3: revise();break;
case 4: seek();break;
case 5: show();break;
case 6: return 0;
}
}
}
void show_view(void)
{
printf("\n");
puts("------通讯录-------");
puts("1、增加联系人");
puts("2、删除联系人");
puts("3、修改联系人");
puts("4、查找联系人");
puts("5、显示所有联系人");
puts("6、退出程序");
}
void add(void)
{
if(50 <= order)
{
printf("系统正在升级,请稍后!\n");
return;
}
else
{
printf("请输入姓名:\n");
scanf("%s",Name[order]);
stdin->_IO_read_ptr=stdin->_IO_read_end;
printf("请输入电话:\n");
scanf("%s",Num[order]);
stdin->_IO_read_ptr=stdin->_IO_read_end;
printf("请输入性别(w/m):\n");
scanf("%s",Sex[order]);
order++;
printf("添加成功!\n");
}
}
void delete(void)
{
char name[20]={};
printf("输入要删除人的姓名:\n");
scanf("%s",name);
for(int i=0;i<order;i++)
{
if(0==(strcmp(Name[i],name)))
{
for(int j=i;j<order;j++)
{
strcpy(Name[j],Name[j+1]);
strcpy(Num[j],Num[j+1]);
strcpy(Sex[j],Sex[j+1]);
}
printf("删除成功\n");
break;
}
else
{
printf("查无此人,删除失败");
break;
}
}
order--;
}
void revise(void)
{
char name[20]={},num[12]={},sex[2]={};
printf("输入要修改人的姓名:\n");
scanf("%s",name);
for(int i=0;i<order;i++)
{
if(0==strcmp(Name[i],name))
{
stdin->_IO_read_ptr=stdin->_IO_read_end;
printf("请输入修改后姓名:\n");
scanf("%s",name);
strcpy(Name[i],name);
stdin->_IO_read_ptr=stdin->_IO_read_end;
printf("请输入修改后电话:\n");
scanf("%s",num);
strcpy(Num[i],num);
stdin->_IO_read_ptr=stdin->_IO_read_end;
printf("请输入修改后性别(w/m):\n");
scanf("%c",sex);
strcpy(Sex[i],sex);
break;
}
printf("没有此人!\n");
}
}
void seek(void)
{
char key[20]={};
printf("输入要查找的信息:\n");
scanf("%s",key);
int i=strlen(key),cnt1=0;
for(int j=0;j<order;j++)
{
if(NULL!=strstr(Num[j],key)||NULL!=strstr(Name[j],key))
{
cnt1++;
printf("%s %s ",Name[j],Num[j]);
if(*Sex[j]=='w')
{
printf("女");
}
else
{
printf("男");
}
printf("\n");
}
}
if(cnt1==0)
{
printf("找不到!\n");
}
}
void show(void)
{
for(int i=0;i<order;i++)
{
printf("%s %s ",Name[i],Num[i]);
if(*Sex[i]=='w')
{
printf("女");
}
else
{
printf("男");
}
printf("\n");
}
}
优化方法:
#include <stdio.h>
#include <string.h>
#include <getch.h>
#include <stdlib.h>
#include <unistd.h>
static int count = 0; // 有效联系人
static char name[50][20] = {};
static char tel[50][12] = {};
static char sex[50] = {};
// 按任意键继续
void anykey_continue(void)
{
puts("请按任意键继续...");
stdin->_IO_read_ptr = stdin->_IO_read_end;
getch();
}
// 打印提示信息
void msg_show(const char* msg,float sec)
{
printf("%s",msg);
fflush(stdout);
usleep(sec*1000000);
}
int menu(void)
{
system("clear");
puts("****欢迎使用指针通讯录****");
puts("1、添加联系人");
puts("2、删除联系人");
puts("3、修改联系人");
puts("4、查找联系人");
puts("5、显示联系人");
puts("6、退出通讯录");
puts("**************************");
printf("请输入指令:");
int cmd = getch();
printf("%c\n",cmd); // 回显
return cmd;
}
void add(void)
{
if(50 <= count)
{
printf("系统正在升级,请稍候!\n");
return;
}
int i = 0;
while(sex[i]) i++;
printf("请输入姓名、性别、电话:");
scanf("%s %c %s",name[i],&sex[i],tel[i]);
count++;
msg_show("联系人添加成功!",1.5);
}
void del(void)
{
char key[20] = {};
printf("请输入要删除的联系人姓名:");
scanf("%s",key);
for(int i=0; i<50; i++)
{
if(sex[i])
{
if(0 == strcmp(key,name[i]))
{
sex[i] = 0;
count--;
msg_show("联系人删除成功!\n",1.5);
return;
}
}
}
msg_show("查无此人,请检查!\n",1.5);
}
void mod(void)
{
printf("%s\n",__func__);
}
void find(void)
{
char key[20] = {};
printf("请输入要查找的关键字:");
scanf("%s",key);
for(int i=0; i<50; i++)
{
if(sex[i])
{
if(strstr(name[i],key) || strstr(tel[i],key))
{
printf("%s %s %s\n",
name[i],'w' == sex[i]?"女":"男",tel[i]);
}
}
}
anykey_continue();
}
void show(void)
{
for(int i=0; i<50; i++)
{
if(sex[i])
{
printf("%s %s %s\n",
name[i],'w' == sex[i]?"女":"男",tel[i]);
}
}
anykey_continue();
}
int main(int argc,const char* argv[])
{
for(;;)
{
switch(menu())
{
case '1': add(); break;
case '2': del(); break;
case '3': mod(); break;
case '4': find(); break;
case '5': show(); break;
case '6': return 0;
}
}
}
预处理指令:
程序员所编写的代码不能被真正的编译器所编译,需要先经过一段程序编译一下
翻译的过程称为预处理,负责翻译的程序称为预处理器,被翻译的语句叫做预处理指令,以#开头的都是预处理指令
查看预处理的结果:
gcc -E codo.c 把预处理的结果显示到终端
gcc -E codo.c -o code.i 把预处理的结果存储到.i预处理文件
预处理指令的分类:
#include 头文件导入(拷贝)
#include <> 从系统指定路径查找头文件
#include "" 从当前工作路径查找,找不到再从系统指定路径查找
-I path 可以指定要查找的路径path
还可以通过设置环境变量来指定路径
#define 定义宏
宏常量:
#define MAX 50
优点:提高代码可扩展性,提高可读性,提高了安全性,还可以和case配合
注意:定义宏常量不要加分号,一般宏名全部大写
预定义好的宏常量:
printf("%s\n",__func__) 获取函数名
printf("%s\n",__FILE__) 获取文件名
printf("%d\n",__LINE__) 获取行数值
printf("%s\n",__DATE__) 获取日期
printf("%s\n",__TIME__) 获取执行时的日期
宏函数:
是带参数的宏
不是真正意义上的函数,没有发生传参,也没有返回值,也不会去检查参数类型
#define SUM(a,b) a+b
1、先把代码中出现宏函数的位置,替换成宏函数后面的语句
2、再把代码中使用的参数替换成调用者的参数
注意:宏的内容保证在同一行,如果要换行,要在每一行末尾添加续行符\
宏函数的二义性:
由于宏函数代码位置、附近的值、参数各种原因的影响,会导致宏函数有不同的解释,这就叫做宏的二义性
如何避免宏的二义性
每个参数加小括号,整体也加小括号,不要在宏函数的参数中使用自变运算符