C语言入门-补充知识点
提供两个参考网站:
(1) https://www.dotcpp.com/course/lib/
(2)https://zh.cppreference.com/w/%e9%a6%96%e9%a1%b5
1. 常量定义的方式:
(1)字面量 / 直接量:整型常量、实型常量、字符常量、字符串常量
字面量/直接量,英文都是literal,源代码中对固定值的表示方法,可以是整数、浮点数、字符或字符串等。在java中,这二者也只是创建方式存在不同,字面量使用了new。
由此也可以知道,所有常量作为编译时已知的固定值,它们是不可变的,位于低地址区域(< 0x8048000)。
(2)符号常量:使用一个标识符表示一个常量,增强可读性
特殊的:C99 const定义的常变量(constant) 但可以被间接修改(换个变量,指针、地址等)const int A = 100;
枚举常量:enum X {A, B, C}; 关键字enum,X是枚举类型名字,枚举名字A,B,C是int型常量符号(值默认从0依次到n;也可以指定值,指定值后的局部仍是顺次递增1的),大括号后记得带好分号,枚举类型表示为 enum X。
在C语言中枚举量本质是以整数来计算或输入输出,枚举量可以作为值。一般还有个套路:在枚举量后面再多加一个NumX就可以用来表明这里面有多少枚举量。
枚举类型只适用于有意义排比的名字等极少场合,因此实际不常用。但枚举比宏好:枚举是int型,宏是没有类型的。(java的枚举类型比C的更好用)
自定义宏(macro)(常量、函数、编译预处理) #define
编译预处理指令: # ,打个戳 —— 不属于C语言的成分,其它语言也可以使用
定义宏 define
使用:#define 宏的名字 宏的值
(gcc命令保留编译临时文件:gcc xxx.c --save-temps 【.c .i .s .o .out】)
注意点:
(1)编译预处理时把文本中字符串(双引号)外的所有宏的名字全部替换成对应宏的值(使用语句注意不要加分号,易导致代码多分号) ;
(2)一个宏的值包含有其它宏的名字,也会被替换 ;
(3)宏的值会把空格也计入,但出现的注释不会被当作宏的值的一部分,可以放心 ;
(4)一个宏的值超过一行,最后一行之前的每行行末需要加 \ 。
没有值的宏——用于条件编译,后面有其它编译预处理指令检查这个宏是否被定义过了,如果定义过了就执行一代码,否则就执行二代码。
预先定义的宏——符号前后各带有两条下划线,如:
__ LINE __ (获取源文件中当前行位置)
__ FILE __ (获取源文件名带路径)
__ func __ (获取当前函数名)
__ DATE __ (编译日期 月、日、年)
__ TIME __ (编译时间)
等
宏的拓展:带参数的宏
大型程序很常见(尤其西方)。
像函数的宏,如:#define cube(x) ((x) * (x) * (x)),效率很高,但牺牲了空间,且不会检查类型【部分宏可以被新的 inline 函数替代,它会检查数据类型】
定义时的原则:一切带好括号,参数出现的每个地方带括号,整个值最后带括号——避免运算优先级导致出错
可以带多个参数,也可以嵌套其它宏: #define MIN(a, b) ((a)>(b)?(b):(a))
可以用来产生新的函数:使用#及##
2. C语言不能用字符类型char存放汉字——
C语言中单引号用来表示字符字面量(占一个字节,编译时对应ascii码),双引号用来表示字符串字面量(占两个字节,编译时对应内存地址,结束符‘\0’)。前者在内存中的低地址范围,在内存中地址小于0x08048000的地址不能访问。因此printf参数使用的是双引号。
如果这样定义:char c = “string”; ,编译时将string的内存地址(4B)给变量c(1B),这样会发生截断(warning警告)。
C语言char类型只能用于存放占一个字节的字符,中文一般占2个字节甚至3个字节,所以C的char不能存中文,必须用字符数组。而在Java中char采用unicode编码占2个字节,一般可以直接存中文。(unicode是固定长度的静态编码字符集;utf-8是一种编码规则 全称unicode transfomation format 8)
3. 常用库函数总结:
echo:提供两个参考网站:
(1) https://www.dotcpp.com/course/lib/
(2)https://zh.cppreference.com/w/%e9%a6%96%e9%a1%b5
C/C++常用头文件及一些常用函数
C
<stdio.h>
printf scanf getchar putchar gets puts
fgets:fgets(s,n,stream) 从流stream读n-1个字符,或遇换行符’\n’为止,把读出的内容,存入s中。与gets不同,fgets在s末尾保留换行符且会检查读取字符最大限制。
fflush
<stdlib.h>
system:发送一个DOS命令
qsort:C语言自带的快速排序函数
malloc realloc free calloc
rand:可以产生伪随机数,默认随机种子是1,所以可以用srand设置随机种子辅助变得更随机(随机种子相同,每次产生随机数相同)。本质上仍无法真正的随机,当需要随机的数据量达到一定规模(如50,0000)时会发现rand数据分布符合正态分布。注意随机数的范围是左闭右开,因此想达到右端点需要通过+1实现。如:设置[m, n]范围的随机整数可用 int num = rand() % (n-m+1) + m。由于rand函数类型是int,本身范围是0~RAND_MAX(stdlib有定义),故随机的小数可以这样做:double num = (double)rand() / RAND_MAX; 现在范围是0 ~ 1,如果范围是[m, n),就再这样:num = m + num * (n - m); 就行了。C没有random函数。
<time.h>
srand:srand随机种子,借助unsigned int型的time(0/NULL)*m实现随时间变化的随机性(flexible),m显然是u int型。如:srand((unsigned int)time(NULL) * 10); 如果这样:srand((unsigned int)getpid()); 在同一个程序中种子值是固定的(fixed)。
<math.h>
pow sqrt abs fabs
fmax fmaxf fmaxl fmin 找两数的较大、较小
fdim 比较第一个参数值是否大于第二个,大于返回差值,否则返回0
<string.h>
strlen strcmp strcpy strcat strchr strstr strncmp strncpy strncat strcasestr
memset: void * memset(void *buffer, int c, int count) 把buffer所指内存区域的前count个字节设置成字符c。
memcpy :拷贝成员
<windows.h>
Sleep
<conio.h>
getch( _getch )
kbhit
C++
< iostream >
cout endl cin
额外的如:
<graphics.h> (安装EasyX图形库后可以使用)
IMAGE
自己项目中写的头文件一般用#include “xxx.h”,原因在于:<>首先搜索编译器头文件所在目录,之后才搜索项目工程文件所在目录,而""搜索顺序正好倒过来。#include “xxx.c”
头文件使用 #ifndef
#define
xxxxxx
#endif
或 #pragma once 避免重复定义头文件中的全局变量(多个源文件都包含同一头文件时),因此也建议头文件不要定义变量。另外注意不同的头文件定义的宏名称要保证不同。
拓展:C++语言STL中的 list 和 map 数据结构(C语言可以用数组实现)
(C++容器)
array:数组
string:字符串 ,头文件 < string >
vector:相当于数组,但有更高级的特性【头文件< vector >】
set:和vector类似,但元素有序且唯一(不可重复),它会自动排序【头文件set】
list:双向链表,foward_list 单链表;存储单列数据的集合,有序可重复【头文件list】
map:< key, value >(映射);存储双列数据的集合,无序,键不可重复、值可重复【头文件map】