- define 易错;只是全局替换
在输入数据时候,遇到以下情况时,认为该数据结束①遇空格,或按回车,或跳格键;②指定宽度结束,如%3d;③遇非法输入
- 类型转换
int i = 5;
float f = i / 2;
df: float f = (float)i / 2;
注意上面的区别
C语言只有整型,实型(浮点精度值),字符型,
无逻辑型——bool
- printf的输出格式:
| %? | 对应的变量类型 |
| %c | char |
| %d | int |
| %f | float |
| %s | string |
| %-nd | int类型占n个位 ,-表示左对齐,不加默认右对齐 |
| %m.nf | float占m位,m=0时不限制总位数。小数点后占n位 |
| %0 | 0代表八进制输出 |
| %x | x代表十六进制输出 |
对int i = 77; 若是077——八进制;0x77——十六进制
现在市面上的智能设备,几乎全是小端CPU,即小数在字节的左侧,00000在右侧,低位在前,高位在后
- scanf读取标准输入
scanf(“%d”,&i);//一定要取地址
fflush(stdin);//清空标准输入缓冲区
scanf函数会返回输入成功地个数
遇到scanf(“%c”),一般在%c前面加一个空格,除非是首位
整形数0~128可以用%c输出为char类型 - 运算符与表达式
总的运算符优先级由高到低:
非、算数运算符、关系运算符、与或、赋值运算符;
非(!)→与(&&)→或(||) 谐音记为“飞鱼火”;
逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算术运算符
! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
一般括号是不加的,提供阅读速度
赋值运算符左边只能放变量
短路运算:
int i= 1;
i&&printf("xxxxx");
整除运算符/:多数C编译系统采取“向零取整”,5/3 = 1,-5/3 = -1;
sizeof()是一个运算符,不是函数!
机试时,如果需要数据校验,一般会提示的;不提示,说明不需要
6. 选择结构
if while 一般都加上{},防止出错
while 有终止条件while(a!=null),
没终止范围【m,n】--用for
大小写转换:
转换为小写:strlwr();
转换为大写:strupr();
- 数组
*(a+i)引用数组元素的方法叫指针法,a[i]引用数组元素的方法叫下标法;
记住,只有用字符串初始化字符数组和(不管以什么形式初始化)数组长度超过字符串长的情况,才有“\0”。
⚠️要区分数组名a和指针p的区别,后者是指针变量,但前者a是指针常量,所以a++操作是行不通的。
char str[14];
str = "I am umbrellalalalala"; //数组名是地址,是常量,不能被赋值
str[] = "I am umbrellalalalala"; //这样赋值也是非法的
//如果是对单个数组元素赋值则没问题:str[0] = "I"
打印数组里的元素时,数组长度是传不过去的,需要额外加一个形参表示数组长度----》void print(int a[],int len ){}
字符数组:char c[10]={'a','b','c'};//这种方法很低效,所以又提供了
char c[10]="hello";//的高效方法
字符数组的空间刚好比元素打多一位就不会出现打印乱码的情况(多的一位用于‘\0’);
打印字符数组时,可不传长度,由while(c[i]){
printf("%c",c[i]); } 即可
scanf一般会忽略空格;所以可以使用gets(c),这就可以给c赋值空格--一次读取一行
puts(c)就是打印字符数组C
8. str系列(初试不重要,机试重要)
主要就是4个函数:strlen(c)--c的长度;
void strcpy(to,*from),从from数组复制给to
int strcmp(str1,str2),比较2个字符串;返回值为>=1,str1大于str2;为0,等长;为<=-1,小于str2(比较的依次是ASCII码值的大小;OJ系统不可直接返回strcmp,需要判断)
strcat(str1,str2),将str2拼接到str1上
- 指针系列
int i;
int *p;//代表一个int* 的地址,变量名是p
&i;//取地址;
*p;//取值
区分指针的其他概念
(1)指针和指针变量
指针就是地址本身,指针变量是存储地址的变量。
(2)重点区分int (* p)[4]和int * p[4]:
前者是指向包含四个元素的一维数组的指针变量;后者是指针数组,包含四个指向整型数据的指针元素。
直接访问和间接访问变量
如何想数组中存放数据?
一开始:for(int i=0; i<n ;i++){
scanf("%d",arr[i]);//错了!应该是&arr[i]
}
fgets(c,sizeof(c),stdin) 与 gets(c)的区别:fgets会在‘\0’前多加上‘\n’;
另外,注意,‘0’ 与 ‘\0’区别
字符数组尾部一般手动加上‘\0’,否则后面会乱码
指针的使用场景:传递和偏移,其他一般不用
传递:void change(int *p);
调用时:change(&i);//就可以修改实参的值
一般的change(int p); change(i);//不能修改实参的值
偏移:*(p+1)
int a[5] = {1,23,34,5};
int* p = a;//p指向a[0]
int j = p ++;//即为j=p; P++;
数组名作为实参传递给子参数时,是弱化为指针的
要在子函数中修改指针,必须将指针地址当成参数
要在子函数中修改变量,必须将变量地址当成参数
-
动态申请空间--堆空间,需要自行管理
void * malloc();所以便于转换成不同类型的指针
free(p);//释放空间,释放的p的地址是不能偏移的;所以可以用其他变量代替p进行操作
p = NULL;//如果不把P置为NULL,则释放后的p成为野指针,c和C++是很忌讳的
-
栈与堆的区别
指针与数组赋值的区别;
指针不能修改某个元素,可以重新指定地址;数组可以修改个别元素(应该是C显性独有的),但不能整体修改
- 当gets与scanf同时出现的易错点
先是scanf读取数据;再是gets读取数据;就需要在中间去除‘\n’、
方法是:char c; scanf("%c",&c);//就可以去除‘\n’;_
递归时,结束条件在递归公式前
- 结构体
struct student{
int age;
char a[20];
} student1,*s2;
结构体大小是4的整数被——因为CPU取空间时是对齐的,所以计算结构体大小多是错误的(因为不一定是4的整数倍);
之所以不能用 —— *s2.age;//是因为‘.’的优先级比*高
而用:s2->age;//这个反而经常用
typedef int INTEGER;//typedef就是用来取别名的,有时用于‘变量名即注释’,有时为了快速开发简化某些步骤
p->age = (p).age的区别:
其中 p->age = (p).age 就是一种语法,没有为什么
比如:英语里的 I am KK,你不能说成 I is KK.
(*p).age = st.age
上述代码有这样一行 p = &st; // p指向st
便有 p = st // 你可以理解“”运算符为打开
于是就出现了"->"运算符,实际上就是C语言提供的语法,就像数组a[1] = *(a+1) 一样
-
C++引用
C语言与C++语言关于形参的区别:
cpp语言更容易修改实参,可以在形参中用&i,C语言并不可以!;C语言需要用指针,比较繁琐
-
条件运算符&逗号运算符&位运算符
a>b?a:b《--这就是条件运算符
if(a,b){} 就是逗号运算符
>>:右移,对于负数来说,偶数除2;奇数先-1,再除2; -
补码
无符号数,都是正数,必须如此--printf("\u",i);有符号数,如int,0代表+;1代表-
负数的二进制是补码形式,1开头;补码就是用来表示负数的