输出缓冲区:
当我们使用标准库的输出系列函数打印数据到屏幕,数据并不会立即显示到屏幕上,而先存储到一块内存中,我们把这块内存称为输出缓冲区,等满足相关条件后,再从缓冲区中显示到屏幕,相关条件有:
1、从输出状态切换到输入状态。
2、缓冲区满了,1k=1024个字节,系统会把缓冲区中所有数据一起显示到屏幕了。
3、程序正常结束时,系统会把缓冲区中所有数据一起显示到屏幕了。
4、遇到'\n'时,'\n'前面的数据会立即显示到屏幕上。
5、调用fflush(stdout) 强制刷新,会把立即输出缓冲区中所有数据一起显示到屏幕了。
总结:缓冲区机制的目的是为了提高输入输出效率
实现一个动态时钟,在屏幕上动态显示出 hh:mm:ss
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
int main() {
int sec = time(NULL);
while (true) {
system("clear");
printf("%d:%d:%d",(sec/3600+8)%24,sec/60%60,sec%60);
fflush(stdout);
sleep(1);
sec++;
}
}
输入缓冲区:
当我们从终端输入数据给程序时,系统并没有立即把数据交给程序读取,而先存储到了一块内存中,我们这块内存称为输入缓冲区,直到我们按下Enter键时,系统才会把缓冲区中的数据给程序读取。
当我们输入的数据过多,或者类型不匹配,标准的输入系列函数就会读取失败,或只读取一部分,剩余的数据就会残留缓冲区中,影响后续数据的输入,当我们发现这情况情况后,应先清理输入缓冲区,后续的数据才能正常输入
清理输入缓冲区的方式:
方法1:
while('\n' != getch()); // 清空缓冲区,直到按下回车结束
方法2:正则表达式
scanf("%*[^\n]"); // 从缓冲区中读取任意类型数据并丢弃,直到遇到'\n'
scanf("%*c"); // 从换乘区中读取一个字符并丢弃
方法3:
stdin->_IO_read_ptr = stdin->_IO_read_end;
// 设置输入缓冲区的位置指针到缓冲区末尾,此时缓冲区会被操作系统自动清空
注意:
1、方法3只能在Linux系统中使用
2、如果输入缓冲区中本来就没有垃圾数据,使用方法1和方法2就需要你手动多输入一个'\n'作为垃圾数据,程序才能往下走
字符:
什么是字符:
字符就是符号或图案,但在计算机中以整数形式存在,当需要显示时,会根据ASCII表中的对应关系显示出相应的符号或图案。
在C语言中使用char类型的变量存储字符的ASCII码值,也就是使用整数进行模拟字符,标准的ASCII码表的范围是:0127,共128个字符,其他的语种,使用-128-1进行设计字符编码,比如中文的汉字,使用的是2~3字节存储一个汉字。
重要的字符:
'\0' ASCII值是 0 空字符 字符串的结束标志
'0' ASCII值是 48
'A' ASCII值是 65
'a' ASCII值是 97
输出:
printf(“%c”,ASCII值);
putchar(ASCII值);
字符的输入:
char ch;
scanf("%c",&ch);
ch = getchar();
注意:
当先输入数值型数据(整数形、浮点型),再输入字符型数据时,前一次的输入会残留一个'\n'或空格,影响字符型数据的输入,是缓冲区在影响字符的输入
有以下方法解决:
方法1:增加一个空白字符的接收函数
scanf("%*c");
getch();
getchar();
方法2:在%c前面增加一个空格
scanf(" %c");
方法3:全部清空输入缓冲区
stdin->_IO_read_ptr = stdin->_IO_read_end;
判断字符类型的函数:
函数名 | 函数功能 |
---|---|
isalnum() | 当字母或数字字符时, 返回真值 |
isalpha() | 当字母字符时, 返回真值 |
iscntrl() | 当控制字符时, 返回真值 |
isdigit() | 当数字字符时, 返回真值 |
isgraph() | 当非空格可打印字符时, 返回真值 |
islower() | 当小写字母字符时, 返回真值 |
isprint() | 当可打印字符时, 返回真值 |
ispunct() | 当标点字符时, 返回真值 |
isspace() | 当空格字符时, 返回真值 |
isupper() | 当大写字母字符时, 返回真值 |
isxdigit() | 当十六进制字符时, 返回真值 |
串型结构:
由若干个相同类型的数据组成顺序表(数组),在数据的末尾有一个结束标志,在使用这种数组时,可以不关心数组的长度。并且串型结构的处理都是批量性的
#include <stdio.h>
void show_string(int arr[]) {
for (int i = 0; arr[i] != ~0; ++i) {
printf("%d ",arr[i]);
}
}
int main() {
int arr[] = {33,5,0,63,34,23,5,~0,32,23,56};
show_string(arr);
}
字符串:
什么是字符串:
由字符类型组成的串型结构,它的结束标志是'\0',使用它可以存储单词、句子、文章、汉字等更丰富的信息,一般使用char类型的数组存储。
// 定义字符串时,要为'\0'预留位置
char arr1[] = {'H','e','l','l','o','\0'};
char arr2[10] = {'H','e','l','l','o'};
字符串字面值:
1、"由双引号包括着的若干个字符"
2、它是以常量字符数组的形式存在,末尾隐藏着一个'\0'。
3、它们会被存储在text内存段,一旦强行修改就会出现段错误。
4、使用指针指向字符串字面值时,一定要用const加以保护,防止出现段错误,宁可出现编译时的错误,也不要出现运行时的错误。
5、编译器会优化它的存储,相同的字符串字面值,只会存储一份在text内存段中。
6、最常用的是用它给字符数组初始化,char arr[] = "hello" 编译器会自动拷贝字符串到数组的内存中(包括'\0'),完成初始化就有了两份字符串存储在内存中,一份存储在stack\data,另一份还存储在text。
注意:使用字符串字面值给字符数组赋值,只能在定义字符数组时使用,这是编译器帮忙完成拷贝的,在完成字符数组的定义后,只能使用strcpy函数对字符串进行赋值。memcpy
#include <string.h>
int main() {
char str[] = {'a','b','c','1','2',0};
char str1[5] = {'A','B','c','1','2'};
str[0] = 'A';
printf("%s\n",str);
printf("%s\n","hehehedijfdio");
printf("%s\n","hehehedijfdio");
const char* p = "hehe";// text内存段
const char* p1 = "hehe";// text内存段
printf("%p %p %s\n",p,p1,p);
// p[0] = 'H';
char str2[] = "hello world hehexiaixijefikdfm";
str2[1] = 'E';
// str2 = "hehe";
strcpy(str2,"xixihaha");
printf("%s\n",&str2[9]);
}
字符串的输出:
printf("%s",字符串的首地址);
puts(字符串的首地址); // 输出完字符串后会再输出一个\n
字符串的输入:
scanf("%s",存储字符串的首地址);
缺点:不能输入带有空格的字符串
char *gets(char *s);
返回值:就是s,为了链式调用
缺点:直接从终端中接收字符数据,遇到'\n',可以接收空格字符,但是它不检查数据的长度跟存储空间的关系,所以很容易接收过长产生段错误、脏数据,官方编译器不建议使用该函数,会产生警告
char *fgets(char *s, int size, FILE *stream);
功能:可以从指定文件stream中读取不超过size-1个字符会自动在末尾添加'\0',并存储到s中,返回值也是s,为了链式调用
stream: 数据的来源,写stdin即可 stdout 一切皆文件
size:最多只能读取size-1个字符,必定会为'\0'预留位置
缺点1:如果输入的字符个数不足size-1个时,会把最后输入的'\n'一起接收
缺点2:如果输入的字符个数超过size-1个时,超出部分的字符数据会继续残留在输入缓冲区中,会继续影响后序的输入
解决方法:
char usr[6] = {};
printf("请输入字符串:");
fgets(usr,6,stdin);
int len = -1;
// 计算出'\0'下标为len
while(usr[++len]);
// 检查'\0'前面是否是'\n'
if('\n' == usr[len-1]) {
// 证明输入不足size-1
usr[len-1] = '\0';
} else {
// 证明输入超过size-1个,\n在缓冲区中,有残留
// 清理输入缓冲区
//while('\n' != getch());
stdin->_IO_read_ptr = stdin->_IO_read_end;
}
#include <stdio.h>
char* my_fgets(char *s, int size) {
if(NULL == s) return NULL;
fgets(s,size,stdin);
int len = -1;
while(s[++len]);
if('\n' != s[len-1]) {
stdin->_IO_read_ptr = stdin->_IO_read_end;
} else {
s[len-1] = '\0';
}
return s;
}
int main() {
char str[10] = {};
my_fgets(str,10);
printf("---%s---\n",str);
}
操作字符串的常用函数:
size_t strlen(const char *s);
功能:计算字符串的长度,不包括'\0'
char str[] = "he\0he \ni";
printf("strlen:%d\n",strlen(str)); 2
printf("sizeof:%d\n",sizeof(str)); 9
printf("sizeof:%d\n",sizeof("xixixx")); 7
printf("strlen:%d\n",strlen("xixixx")); 6
char* p = "xixixx";
printf("sizeof:%d\n",sizeof(p)); 指针 4\8
printf("strlen:%d\n",strlen(p)); 6
简答题:sizeof(运算符)跟strlen (函数)的区别?
char *strcpy(char *dest, const char *src);
功能:把字符串src拷贝到dest处,相当于 = 运算符
注意:会把src末尾的'\0'一起拷贝过来
char *strcat(char *dest, const char *src);
功能:把src字符串追加到dest的末尾 相当于 += 运算符
注意:从dest的\0开始追加src,并且会把src的\0一起追加过来
int strcmp(const char *s1, const char *s2);
功能:按字典序比较两个字符串
s1 > s2 返回正数
s1 < s2 返回负数
s1 == s2 返回0
逐个字符进行比较,一旦出结果立即结束,后面的不再比较
重点笔试题:
自己实现 strlen、strcpy、strcat、strcmp四个函数的功能(不能调用str系列函数)
size_t my_strlen(const char *s) {
size_t len = 0;
while (*s++) len++;
return len;
}
char* my_strcpy(char *dest, const char *src) {
if (dest == NULL || src == NULL) return NULL;
while (*dest++ = *src++);
return dest;
}
char* my_strcat(char *dest, const char *src) {
if (dest == NULL || src = NULL) return NULL;
while (*++dest);
while (*dest++ = *src++);
return dest;
}
int my_strcmp(const char *s1, const char *s2) {
do {
if (*s1 < *s2) return -1;
else if (*s1 > *s2) return 1;
} while (*s1++ && *s2++);
return 0;
}
字符串相关函数:
int atoi(const char *nptr);
功能:字符串转int类型
long atol(const char *nptr);
功能:字符串转long类型
long long atoll(const char *nptr);
功能:字符串转long long类型
double atof(const char *nptr);"2.4"
功能:字符串转double类型
char *strstr(const char *haystack, const char *needle);
功能:查找haystack中是否存在needle
返回值:needle第一次在haystack出现的位置,如果找不到返回NULL
"abcdefcd" "cad"
char *strchr(const char *s, int c);
功能:查找字符串s中是否有字符c。
返回值:c在s中第一次出现的位置,如果找不到返回NULL。
int sprintf(char *str, const char *format, ...);
功能:把任意类型的数据输出到str中 把任意类型的数据拼接成字符串
返回值:字符串str的长度
int sscanf(const char *str, const char *format, ...);
功能:从str中读取任意类型数据 从字符串中解析任意类型的数据
返回值:成功读取到的变量个数
int n = 10;
double d = 3.14;
long long l = 444;
char str[256] = {};
sprintf(str,"学号:%d 分数:%lf 总分:%lld\n",n,d,l);
printf("--%s--",str);
int n1 = 0;
double d1 = 0;
long long l1 = 0;
sscanf(str,"学号:%d 分数:%lf 总分:%lld",&n1,&d1,&l1);
printf("%d %lf %lld\n",n1+10,d1,l1);
电子通讯录项目:
联系人信息:
姓名、性别、联系电话
功能:
1、添加联系人
2、删除联系人 (按名字删除)
3、修改联系人信息 (按名字查找)
4、查询联系人 (按名字或者电话查询 选做:支持模糊查询)
5、显示所有联系人
6、该通讯录最多只存储100个联系人
7、选做:考虑数据存储在堆内存中
#include <stdio.h>
#include <stdbool.h>
#include <getch.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
char name[100][20], sex[100], tel[100][12];
size_t count = 0;
float sec = 2.2; // 提示信息显示时间
void clear_stdin() {
stdin->_IO_read_ptr = stdin->_IO_read_end;
}
char get_op(const char start, const char end) {
clear_stdin();
printf("请输入指定选项[%c,%c]\n", start, end);
while (true) {
char op = getch();
if (start <= op && op <= end) {
printf("%c\n", op);
return op;
}
}
}
char* get_str(char* str, size_t size) {
clear_stdin();
size_t len = strlen(fgets(str, size, stdin));
if (str[len - 1] == '\n') str[len - 1] = '\0';
return str;
}
char* sex_to_get(const char sex) {
if (sex == 'w' || sex == 'W') {
return "女";
} else if (sex == 'm' || sex == 'M') {
return "男";
}
return "性别未知";
}
char get_sex() {
clear_stdin();
printf("请输入性别(w女/m男):");
while (true) {
char sex = getch();
if ('w' == sex || 'W' == sex || 'm' == sex || 'M' == sex) {
printf("%s\n", sex_to_get(sex));
return sex;
}
}
}
void put_str(const char* msg, float sec) {
printf("%s\n", msg);
usleep(1000000 * sec);
}
void anykey_continue() {
clear_stdin();
printf("请按任意键继续...");
getch();
}
char menu() {
system("clear");
puts("===欢迎使用电子通讯录===");
puts("1、添加 2、删除");
puts("3、修改 4、查询");
puts("5、遍历 6、退出");
puts("========================");
return get_op('1', '6');
}
void add() {
if (count >= 100) {
put_str("通讯录人数已满!", sec);
return ;
}
for (int i = 0; i < 100; ++i) if (sex[i] == 0) {
printf("请输入新联系人姓名:");
get_str(name[i], sizeof name[0]);
sex[i] = get_sex();
printf("请输入新联系人电话:");
get_str(tel[i], sizeof tel[0]);
put_str("添加联系人成功!",sec);
count += 1;
return ;
}
}
void del() {
if (count == 0) {
put_str("通讯录为空!", sec);
return ;
}
char key[20];
printf("请输入想要删除的联系人姓名:");
get_str(key, sizeof key);
for (int i = 0; i < 100; ++i) if (sex[i]) {
if (strcmp(key, name[i])) {
printf("%s %s %s\n", name[i], sex_to_get(sex[i]), tel[i]);
sex[i] = 0;
count -= 1;
put_str("删除成功!", sec);
return ;
}
}
put_str("查无此人删除失败!", sec);
}
void modify() {
if (count == 0) {
put_str("通讯录为空!", sec);
return ;
}
char key[20];
printf("请输入想要删除的联系人姓名:");
get_str(key, sizeof key);
for (int i = 0; i < 100; ++i) if (sex[i]) {
if (strcmp(name[i], key) == 0) {
suc = true;
}
}
put_
put_
}
void query() {
char key[20];
printf("请输入要查询的关键字:");
get_str(key, sizeof key);
bool suc = false;
for (int i = 0; i < 100; ++i) if (sex[i]) {
if (strstr(name[i], key) != NULL && strstr(tel[i], key) != NULL) {
suc = true;
printf("%s %s %s\n", name[i], sex_to_get(sex[i]), tel[i]);
}
}
if (suc) {
anykey_continue();
} else {
put_str("查无此人!", sec);
}
}
void show() {
if (count == 0) {
put_str("暂无联系人...",sec);
return ;
}
for (int i = 0; i < 100; ++i) if (sex[i]) {
printf("%s %s %s\n", name[i], sex_to_get(sex[i]), tel[i]);
}
anykey_continue();
}
int main() {
while (true) {
int op = menu() - '0';
if (op == 1) {
add();
} else if (op == 2) {
del();
} else if (op == 3) {
modify();
} else if (op == 4) {
query();
} else if (op == 5) {
show();
} else {
break;
}
}
}
标签:字符,const,int,高级,C语言,char,str,printf
From: https://www.cnblogs.com/sleeeeeping/p/18174687