C标准库

标准库详细的可以在菜鸟查到
菜鸟教程链接

#include<assert.h>
以前在字符操作中有所用到
assert(src!=NULL);//该功能称为断言,当条件为假的时候,就会出现断言错误,显示错误信息
assert在系统定义中是个宏,虽然看起来是个函数,其实是个宏函数
	
如果程序中定义了NDEBUG宏,则所有的断言会被空语句代替

一个项目:
   调试阶段称为debug版本 
   		在这个阶段程序员为了找出问题,要详细报错,就会写assert
		所以这个阶段不会定义NDEBUG宏 
	上线阶段称为release版本
		上线阶段定义NDEBUG,因为在调试阶段我们已经用assert达到了目的,找出了错误并解决了,
		人为一句句删除assert是不合理的。而定义NDEBUG后,
		程序中的assert就不会去测试(某种意义上,定义了NDEBUG这个宏,就是删除了assert的有关语句),
		提高了程序效率。
	gcc -D NDEBUG x.c    //在命令行定义宏测试    

断言一般不用&&连接条件,尽量分开来写,因为容易判断不出来哪个错哪个对
不要执行有意义的语句i++之类    assert(i++>0);
assert写完一般空一行(编程习惯)
#include <stdio.h>
#include <assert.h>
//程序的美观和阅读性  空格 空行
size_t mylen(const char *s){
	assert(s!=NULL);//断言  函数  宏函数

	size_t len = 0;
	for(;s[len]!='\0';len++);
	return len;
}


int main(){
	printf("%u\n",mylen("Hello"));
	printf("%u\n",mylen(NULL));//开发或者高度阶段有这样的代码
	//上线之后肯定是没有
	
	return 0;	
}

//结果返回为:
5
a.out: try.c:5: mylen: Assertion `s!=((void *)0)' failed.
已放弃 (核心已转储)

#include<ctype.h>
int isalnum(int c)   该函数检查所传的字符是否是字母和数字。
int isspace(int c)   该函数检查所传的字符是否是空白字符。
空白字符是指: \n  \t  空格等 看不见的。
....还有很多,用到及查
这些函数接受 int 作为参数,它的值必须是 EOF 或表示为一个无符号字符。
如果参数 c 满足描述的条件,则这些函数返回非零.如果参数 c 不满足描述的条件,则这些函数返回零。
#include <stdio.h>
#include <ctype.h>

int main(){
	int ret = isalnum('a');
	printf("%d\n",ret);
	ret = isalnum('*');
	printf("%d\n",ret);
	
	return 0;	
}


//返回
8 
0
两个转换函数:
int tolower(int c)
该函数把大写字母转换为小写字母。
int toupper(int c)
该函数把小写字母转换为大写字母。

用assert自己实现上面的两个转换函数:
'A'  65   'a'  97   '0'  48   '\0' 0
int tolower(int c){
	assert(c >= 'A');
	assert(c <= 'Z');
	return c-'A'+'a';
}
int toupper(int c){
	assert(c >= 'a');
	assert(c <= 'z');
	return c-'a'+'A';
}

c语言的函数:传参
char short -> int 自动转换
float -> double  

#include<errno.h>

#include<errno.h>  //声明extern int errno;全局了
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

当系统调用(函数)失败时才能用errno,用户自建的函数不能用这个来查询

strerror(errno);//用来查看错误信息,包含在string.h中
#include <stdio.h>
#include <errno.h>  //声明了全局部变量  extern int errno;
#include <stdlib.h>
#include <string.h>


int main(){
	printf("%d\n",errno);   // 打印0,这时候没错误,0是success
	int *p = malloc(0xFFFFFFFF);
	if(p == NULL){//malloc失败  errno!=0
		//printf("malloc failed!\n");	
		printf("%d\n",errno);//  打印了12
		printf("%s\n",strerror(errno));	  //Cannot allocate memory  无法分配内存
	}
	

	FILE *fp = fopen("a.txt","r");  //a.txt是不存的
	if(fp == NULL){
		printf("%d\n",errno);  //打印了2
		//printf("fopen a.txt failed!\n");	
		printf("%s\n",strerror(errno));  //No such file or directory
	}

	p = malloc(4);//malloc成功 不会把errno设置成0
	if(p != NULL){
		puts("malloc没有失败!\n");	//实际上malloc是成功的,这个也会打印,按理说errno应该是0
	}
	
	/*	errno只能用于获取错误信息,不能用于判断调用是否成功
	如果一个函数调用成功,其实是不会设置errno的
	如果之前errno就是非0,后面用的时候虽然是成功调用,但是errno的值没有改变,还是之前的那个状态,所以还是错*/
	
	if(errno != 0){
		printf("不能用errno!=0来判断失败!\n");  //这里也会打印
	}
	
	
	//查看error中数字代表的错误意思
	printf("--------------------\n");
	int n = 0;
	for(n=0;n<100;n++){
		printf("%2d : %s\n",n,strerror(n));	
	}
	/*--------------------
	 0 : Success
	 1 : Operation not permitted
	 2 : No such file or directory
	 3 : No such process
	 4 : Interrupted system call
	 5 : Input/output error
	 6 : No such device or address
	 7 : Argument list too long
	 8 : Exec format error
	 9 : Bad file descriptor
	10 : No child processes
	11 : Resource temporarily unavailable
	12 : Cannot allocate memory
	13 : Permission denied
	14 : Bad address
	15 : Block device required
	16 : Device or resource busy
	17 : File exists
	18 : Invalid cross-device link
	19 : No such device
	20 : Not a directory
	21 : Is a directory
	22 : Invalid argument
	23 : Too many open files in system
	24 : Too many open files
	25 : Inappropriate ioctl for device
	26 : Text file busy
	27 : File too large
	28 : No space left on device
	29 : Illegal seek
	30 : Read-only file system
	31 : Too many links
	32 : Broken pipe
	33 : Numerical argument out of domain
	34 : Numerical result out of range
	35 : Resource deadlock avoided
	36 : File name too long
	37 : No locks available
	38 : Function not implemented
	39 : Directory not empty
	40 : Too many levels of symbolic links
	41 : Unknown error 41
	42 : No message of desired type
	43 : Identifier removed
	44 : Channel number out of range
	45 : Level 2 not synchronized
	46 : Level 3 halted
	47 : Level 3 reset
	48 : Link number out of range
	49 : Protocol driver not attached
	50 : No CSI structure available
	51 : Level 2 halted
	52 : Invalid exchange
	53 : Invalid request descriptor
	54 : Exchange full
	55 : No anode
	56 : Invalid request code
	57 : Invalid slot
	58 : Unknown error 58
	59 : Bad font file format
	60 : Device not a stream
	61 : No data available
	62 : Timer expired
	63 : Out of streams resources
	64 : Machine is not on the network
	65 : Package not installed
	66 : Object is remote
	67 : Link has been severed
	68 : Advertise error
	69 : Srmount error
	70 : Communication error on send
	71 : Protocol error
	72 : Multihop attempted
	73 : RFS specific error
	74 : Bad message
	75 : Value too large for defined data type
	76 : Name not unique on network
	77 : File descriptor in bad state
	78 : Remote address changed
	79 : Can not access a needed shared library
	80 : Accessing a corrupted shared library
	81 : .lib section in a.out corrupted
	82 : Attempting to link in too many shared libraries
	83 : Cannot exec a shared library directly
	84 : Invalid or incomplete multibyte or wide character
	85 : Interrupted system call should be restarted
	86 : Streams pipe error
	87 : Too many users
	88 : Socket operation on non-socket
	89 : Destination address required
	90 : Message too long
	91 : Protocol wrong type for socket
	92 : Protocol not available
	93 : Protocol not supported
	94 : Socket type not supported
	95 : Operation not supported
	96 : Protocol family not supported
	97 : Address family not supported by protocol
	98 : Address already in use
	99 : Cannot assign requested address
*/

	return 0;	
}

#include<float.h>

5.25
101.01  ===> 1.0101 * 2^2
	符号位  
	尾数   
	指数位  
float.h有一个特定的宏,详细的可以看上面的网站

#include<limits.h>

很多宏:limits.h 头文件决定了各种变量类型的各种属性
CHAR_BIT	8	定义一个字节的比特数。
SCHAR_MIN	-128	定义一个有符号字符的最小值。
SCHAR_MAX	127	定义一个有符号字符的最大值。
UCHAR_MAX	255	定义一个无符号字符的最大值。
CHAR_MIN	0	定义类型 char 的最小值,如果 char 表示负值,则它的值等于 SCHAR_MIN,否则等于 0。
CHAR_MAX	127	定义类型 char 的最大值,如果 char 表示负值,则它的值等于 SCHAR_MAX,否则等于 UCHAR_MAX。
MB_LEN_MAX	1	定义多字节字符中的最大字节数。
SHRT_MIN	-32768	定义一个短整型的最小值。
SHRT_MAX	+32767	定义一个短整型的最大值。
USHRT_MAX	65535	定义一个无符号短整型的最大值。
INT_MIN	-2147483648	定义一个整型的最小值。
INT_MAX	2147483647	定义一个整型的最大值。
UINT_MAX	4294967296	定义一个无符号整型的最大值。
LONG_MIN	-9223372036854775808	定义一个长整型的最小值。
LONG_MAX	9223372036854775807	定义一个长整型的最大值。
ULONG_MAX	1.8446744e+19	定义一个无符号长整型的最大值。


考虑代码的可移植性,建议使用以下类型替换int,long,long 
因为32和64位处理器问题,移植后可能会出现问题
以下面这种形式写相对好

#include <inttypes.h>

int8_t        8bit           uint8_t
int16_t       16bit          uint16_t
int32_t       32bit          uint32_t
int64_t       64bit          uint64_t
#include <stdio.h>
#include <inttypes.h>

//用这些
int main(){
	int8_t a = 10;  //8bit    1个字节
	int16_t b = 10; //16bit   2个字节
	int32_t c = 10; //32bit	  4
	int64_t d = 10; //64bit   8
	
	printf("%d\n",sizeof(int8_t));
	printf("%d\n",sizeof(int16_t));
	printf("%d\n",sizeof(int32_t));
	printf("%d\n",sizeof(int64_t));
	//int long long  char 
	
	return 0;	


//结果   1   2   4   8     
}

#include<time.h>

time_t t = time(NULL)
ctime(&t)
localtime(&t)   //结构体
#include <stdio.h>
#include <time.h>

int main(){
	//例如当你遇到计费问题时,就要涉及到时间问题
	time_t t = time(NULL);//能够获得当前系统时间  一个从1900年1月1日零点0分0秒到当前时间的秒数
	printf("%d\n",t);
	struct tm *pt = localtime(&t);
	//因为从1900开始
	printf("%d-%d-%d\n",1900+pt->tm_year,1+pt->tm_mon,pt->tm_mday);
	printf("%d:%d:%d\n",pt->tm_hour,pt->tm_min,pt->tm_sec);
	
	printf("%s\n",ctime(&t));
	//能够把秒数转为固定格式
	//星期 月 日 时:分:秒 年

	return 0;	
}

//输出
2021-5-16
16:6:53
Sun May 16 16:06:53 2021
man一个localtime   //查看具体内容
struct tm* localime(const time_t *)
struct tm {
   int tm_sec;         /* 秒,范围从 0 到 59        */
   int tm_min;         /* 分,范围从 0 到 59        */
   int tm_hour;        /* 小时,范围从 0 到 23        */
   int tm_mday;        /* 一月中的第几天,范围从 1 到 31    */
   int tm_mon;         /* 月,范围从 0 到 11        */
   int tm_year;        /* 自 1900 年起的年数        */
   int tm_wday;        /* 一周中的第几天,范围从 0 到 6    */
   int tm_yday;        /* 一年中的第几天,范围从 0 到 365    */
   int tm_isdst;       /* 夏令时                */
};

localtime相对于ctime就是能够方便获取时间分量,就是单个数据


#include<locale.h>

#include<setjmp.h>

第一步: 定义变量 jmp_buf buf;
第二步: 设置  int ret = setjmp(buf);如果正常执行该代码,ret==0
	   如果是通过longjmp(buf,num)跳跃,ret==num
第三步: 在任何地方执行  longjmp(buf,num) 都会返回 setjmp(buf)处开始执行代码
#include <setjmp.h>
#include <stdio.h>

jmp_buf buf;
int n=1;

void func(void){
	printf("func begin\n");	
	if(n==0){
		longjmp(buf,1024);//会跳到setjmp()函数处继续执行
	}
}
int  main(){
	
	int ret = setjmp(buf);//0  返回的是longjmp(buf,num)中设置的num

	printf("main:ret = %d\n",ret);//0
	--n;//0
	func();
	
	return 0;	
}

//输出结果
main:ret = 0    
func begin
main:ret = 1024
func begin

#include<signal.h>

signla能完成异步处理,
下面这个程序可以让ctrl c无法结束程序
#include <stdio.h>
#include <signal.h>

void func(int sig){
	printf("捕获信号:%d\n",sig);	
	signal(SIGINT,func);
}
int main(){
	//printf("进程号:%d\n",getpid());
	signal(SIGINT,func);
	while(1);
	return 0;	
}

序号	宏 & 描述
SIGABRT
程序异常终止。
SIGFPE
算术运算出错,如除数为 0 或溢出。
SIGILL
非法函数映象,如非法指令。
SIGINT
中断信号,如 ctrl-C。
SIGSEGV
非法访问存储器,如访问不存在的内存单元。
SIGTERM
发送给本程序的终止请求信号。

命令行输入 :ps aux|grep a.out     里面会有个有个进程号
命令行输入 :kill -2 进程号
如果发生了意外,程序需要去处理这个意外,(类似单片机的中断,它会保存)

回调函数
signal是捕获到信号就调用函数

#include <stdarg.h>

可变长参数列表
void func(int num,...)
va_list ap;
va_start(ap,num);
va_arg(ap,type)
va_end(ap)

#include<stddef.h>

ptrdiff_t
这是有符号整数类型,它是两个指针相减的结果。
size_t
这是无符号整数类型,它是 sizeof 关键字的结果。
wchar_t
这是一个宽字符常量大小的整数类型。
NULL也定义在这个库中
C语言中的NULL
#define  NULL ((void *)0) 
0地址是一个特殊地址,不能访问和修改,所以我们在指针中会用NULL来判断指针是否可读写
#include <stdio.h>
#include <stddef.h>
#include <locale.h>
#include <errno.h>
#include <string.h>
int main(){
	wchar_t str[20] = L"中国万岁";//wchar_t 等宽字符类型  4Byte utf-8
	printf("%u\n",sizeof(wchar_t));//4四个字节,因为是utf-8编码格式
	if(setlocale(LC_CTYPE,"")==NULL){//本地化设置
		printf("%s\n",strerror(errno));
		return -1;
	}
	printf("%ls\n",str);
	return 0;	
}
utf-8中文汉字占2~4个字节
gbk中文汉字占3个字节

#include<stdlib.h>

atof(“3.14”);//字符转为浮点
atol  atoi 等各有功能
#include <stdio.h>

//printf scanf
//sprintf  sscanf
//fprintf  fscanf


int main(){
	char buf[100] = {};
	float n = 3.14159;
	sprintf(buf,"%g",n);//格式化输出到字符串

	printf("%s\n",buf);
	
	return 0;	
}

atexit(func)    回调函数
#include <stdio.h>
#include <stdlib.h>

//回调
void bye(void){
	printf("Goodbye!\n");	
}

int main(){
	printf("main begin\n");
	atexit(bye);//signal  参数都有一个函数指针 回调
	//注册了一个退出函数, 当进程结束之前自动调用被注册好的函数
	//不能修改下面两行代码,要求在输出main end!之后 再输入Goodbye!
	printf("main end!\n");
	return 0;	
}

设置环境变量

env | grep PATH
设置环境变量
sudo vi ~/.bashrc
/PATH
shift+g
PATH=$PATH:.
#include<string.h> memcpy()
#include <stdio.h>
#include <assert.h>
#include <string.h>
//从src处拷贝n个字节的数据到dest中去
void *mymemcpy(void *dest,const void *src,size_t n){
	assert(dest != NULL);
	assert(src != NULL);

	char * pdest = (char *)dest;
	const char * psrc = (const char *)src;

	size_t i;
	for(i=0;i<n;i++){
		*pdest = *psrc;	
		pdest++;
		psrc++;
	}
	return dest;
}

void *mymemmove(void *dest,const void *src,size_t n){
	//
	char *pdest = (char *)dest;
	const char *psrc = (const char *)src;
	size_t i;
	if(psrc+n > pdest){//从后拷贝
		psrc = psrc+n;
		pdest = pdest+n;
		for(i=0;i<n;i++){
			*pdest = *psrc;
			--pdest;
			--psrc;
		}
	}else{//从前往后拷贝
		for(i=0;i<n;i++){
			*pdest = *psrc;
			++pdest;
			++psrc;
		}
	}
	return dest;
}

int main(){
	size_t i;
	int arr[5] = {110,120,119,1024,9527};
	for(i=0;i<5;i++){
		printf("%d ",arr[i]);	
	}
	printf("\n");
	//mymemcpy(arr,arr+1,4*4);//但是src数据也发生了变化   16个字节是4个整数,
	//这里我们把4个数复制到后面的位置
	memmove(arr,arr+1,16);
	//mymemcpy(arr+1,arr,4*4);
	//memcpy(arr+1,arr,16);
	//memmove(arr+1,arr,16);
	for(i=0;i<5;i++){
		printf("%d ",arr[i]);	
	}
	printf("\n");
	return 0;	
}
memcpy(arr+1,arr,4*4);   //全部110   拷贝四个整数到后面位置
memcpy能够实现内存拷贝,但是不会考虑内存重叠问题(pointer aliasing)  
优化版本:
memmove(),就不会有上面那个问题

也有方法src   newsrc  malloc申请动态内存保存,再复制到dest
但是效率比较低
restrict 关键字
用于告诉编译器,两个指针不能指向一个数据
int i=0;
int *s=5
int *b=6
return *a+*b   可能为12
i++ + ++i   未定义的

其实restrict是写给程序员看的,编译器不能做到什么,主要是让程序员知道这个地方指针不能指向一个数据
#include <stdio.h>

int main(){
	int num = 1024;
	int * restrict p = &num;//程序员遵守规则
	int *p1 = &num;//要避免这种情况
	*p1 = 119;
	printf("%d\n",num);	
	printf("%d\n",*p);
	
	return 0;	
}

混合运算 signed和unsigned进行运算,会转换为unsigned运算
#include<stdio.h>
int main(){
	signed int a=-20;
	unsigned int b=10;
	if((a+b)>0){
		printf(">0\n");
	}else{
		printf("<0\n");
	}

	return 0;
}

//结果返回>0

C语言思维导图

在这里插入图片描述

假设有两个整数m,n
不能使用比较运算符
不能使用三目运算符
不能用if
如何比较大小
int m,n;
scanf(“%d %d”,&m,&n);
如果一正一负,较大值是正数
如果符号相等 res=m-n;

//因为二进制编码1是负数,0是正数
int mf = !((m>>31)&1);  //mf=1表示 m为正  0 m为负
int nf = !((n>>31)&1);  //nf=1表示 n为正  0 n为负

int notsame = mf^nf;   //notsame=1 表示 m和n符号不相同
int same = !notsame;   //same=1 表示m和n符号相同

int sub = m-n;//如果一正一负相减 可能溢出
int subf = !((sub>>31)&1);   subf=1表示结果为正

int big = notsame*(mf*m + nf*n) + same*(subf*m + (!subf)*n);
	一正一负  notsame = 1  same = 0
	
都为正  都为负:  notsame = 0  same = 1
big = subf*m + (!subf)*n;
	
一正一负:notsame=1,same=0;
big=mf*m + nf*n

两个数相减的时候可能溢出
很大的正数-很小的负数可能会溢出,所以才有notsame*(mf*m + nf*n)部分

------------------------------------------------------------------------------
项目遵循的规则:
升级项目,把字符项目升级为图形界面的项目  相当于重新开发
MVC三层架构模型:
	M Model模型层   结构体,类,模型的定义层
				结构体定义  作为模型层
				
	V View 视图层   用于和用户进行交互的层次
		用户的输入的数据  作为调用 控制层函数的参数
		
	C Control 控制层   逻辑功能实现的层次
		控制层实现主要的逻辑功能
		通过返回值  或者 传入参数 返回结果给 视图层

程序设计:  经过设计阶段
	文件名
	设计全局变量的名字类型
	设计函数的名字  参数列表,含义,返回值类型  实现的功能
	出错时返回的值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值