首页 > 其他分享 >高级C语言5

高级C语言5

时间:2024-05-06 11:33:35浏览次数:25  
标签:字符 const int 高级 C语言 char str printf

输出缓冲区:

​ 当我们使用标准库的输出系列函数打印数据到屏幕,数据并不会立即显示到屏幕上,而先存储到一块内存中,我们把这块内存称为输出缓冲区,等满足相关条件后,再从缓冲区中显示到屏幕,相关条件有:

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

相关文章

  • 深入了解Appium:Capability 高级配置技巧解析
    简介Appium的除了基础的Capability设置,还提供了许多辅助配置项,用于优化自动化测试。这些配置项旨在执行基础配置之外的附加操作。例如:指定设备别名、设备ID或是设置超时时间等,虽然这些不是必需的选项,但是为了实现更高效的测试,通常也建议依据测试的情况适当的添加。xcuites......
  • 高级C语言2
    计算机的内存长什么样子?1、计算机中的内存就像一叠非常厚的“便签”,一张便签就相当于一个字节的内存,一个字节有8个二进制位2、每一张“便签”都有自然排序的一个编号,计算机是根据便签的编号来访问、使用"便签"3、CPU会有若干个金手指,每根金手指能感知高低电平,高电平转换成1,低电......
  • 高级C语言1
    一、程序的内存分段:(进程映像)​ 当执行程序的运行命令后,操作系统会给程序分配它所需要的内存,并划分成以下内存段供程序使用:text代码段:​ C代码被翻译成二进制指令后存储在可执行文件中,当可执行文件被操作系统执行时,它会把里面的二进制指令(编译后的代码)加载到这个内存段,它里面......
  • 06. C语言指针
    【指针】C语言使用数据名调用数据,数据名相当于C语言的直接寻址,直接寻址只能调用固定数据,而指针是间接寻址,指针存储了另一个数据的地址,使用指针调用数据时首先取指针存储的内存地址,之后使用此地址调用数据,使用间接寻址有如下几点优势:1.统一数据的调用方式,因为指针是调用数据的中间......
  • 标准C语言5
    进制转换:​ 现在的CPU只能识别高低两种电流,只能对二进制数据进行计算。​ 二进制数据虽然可以直接CPU计算识别,但不方便书写、记录,把二进制数据转换成八进制是为了方便记录在文档中。​随着CPU的不断发展位数不断增加,由早期的8位逐渐发展成现在的64位,因此八进制就不能满......
  • 标准C语言4
    一、函数什么是函数:function​函数就是一段具有某一项功能的代码集合,它是C语言中管理代码的最小单位,把具有某项功能的若干行代码封装在函数中方便管理代码且方便重复调用。函数的分类:标准库函数:​ C语言标准委员会为C语言以函数形式提供了一些基础功能,这些函数被封装在li......
  • 标准C语言3
    一、数组什么是数组:​ 数组就是变量的组合,是一种批量定义变量的方式如何定义数组:类型名数组名[数量]; intarr[8];// 相当于定义了8个int类型的变量 inta1,a2,a3,...;访问数组中的变量:数组名[下标]; 下标从0开始,范围0~数量-1遍历数组:与for循环配合,使用循环变量作......
  • 对C语言符号的一些冷门知识运用的剖析和总结
    符号目录符号注释奇怪的注释C风格的注释无法嵌套一些特殊的注释注释的规则建议反斜杠'\'反斜杠有续行的作用,但要注意续行后不能添加空格回车也能起到换行的作用,那续行符的意义在哪?反斜杠的转义功能单引号和双引号字面值,字符串,字符,字符变量的大小为什么sizeof('1')的大小是4?c......
  • 标准C语言2
    二、常量(了解)​ 常量就是程序运行过程中不能改变的量,C语言中常量有:字面值常量、宏常量、枚举常量。字面值常量100 int100l long100ll longlong100u unsignedint100lu unsignedlong100llu unsignedlonglong定义一个宏常量表示100年总共有多少秒,不考虑闰平年 #defin......
  • C语言 子进程段错误后变成僵尸进程
    空指针获取首元素时出现段错误,子进程异常退出,父进程没有处理。#include<stdio.h>#include<unistd.h>intmain(){pid_tpid;pid=fork();if(pid>0){printf("fatherprocessisPID:%d\n",getpid());while(1){......