C语言学习--重难点易错点

  1. define 易错;只是全局替换
    image

在输入数据时候,遇到以下情况时,认为该数据结束①遇空格,或按回车,或跳格键;②指定宽度结束,如%3d;③遇非法输入

  1. 类型转换
    int i = 5;
    float f = i / 2;
    df: float f = (float)i / 2;
    注意上面的区别

C语言只有整型,实型(浮点精度值),字符型,
无逻辑型——bool

  1. 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在右侧,低位在前,高位在后

  1. scanf读取标准输入
    scanf(“%d”,&i);//一定要取地址
    fflush(stdin);//清空标准输入缓冲区
    scanf函数会返回输入成功地个数
    遇到scanf(“%c”),一般在%c前面加一个空格,除非是首位
    整形数0~128可以用%c输出为char类型
  2. 运算符与表达式
    总的运算符优先级由高到低:
    非、算数运算符、关系运算符、与或、赋值运算符;

非(!)→与(&&)→或(||) 谐音记为“飞鱼火”;
逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算术运算符
! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

一般括号是不加的,提供阅读速度
赋值运算符左边只能放变量
短路运算:
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();

  1. 数组
    *(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上

  1. 指针系列
    int i;
    int *p;//代表一个int* 的地址,变量名是p
    &i;//取地址;
    *p;//取值

区分指针的其他概念
(1)指针和指针变量
指针就是地址本身,指针变量是存储地址的变量。

(2)重点区分int (* p)[4]和int * p[4]:
前者是指向包含四个元素的一维数组的指针变量;后者是指针数组,包含四个指向整型数据的指针元素。

直接访问和间接访问变量
image

如何想数组中存放数据?
一开始: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++;

数组名作为实参传递给子参数时,是弱化为指针的
image

要在子函数中修改指针,必须将指针地址当成参数
要在子函数中修改变量,必须将变量地址当成参数

  1. 动态申请空间--堆空间,需要自行管理
    void * malloc();所以便于转换成不同类型的指针
    free(p);//释放空间,释放的p的地址是不能偏移的;所以可以用其他变量代替p进行操作
    p = NULL;//如果不把P置为NULL,则释放后的p成为野指针,c和C++是很忌讳的
    image

  2. 栈与堆的区别
    image

指针与数组赋值的区别;
指针不能修改某个元素,可以重新指定地址;数组可以修改个别元素(应该是C显性独有的),但不能整体修改
image

  1. 当gets与scanf同时出现的易错点
    先是scanf读取数据;再是gets读取数据;就需要在中间去除‘\n’、
    方法是:char c; scanf("%c",&c);//就可以去除‘\n’;_
    image

递归时,结束条件在递归公式前

  1. 结构体
    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) 一样

  1. C++引用
    C语言与C++语言关于形参的区别:
    cpp语言更容易修改实参,可以在形参中用&i,C语言并不可以!;C语言需要用指针,比较繁琐
    image

  2. 条件运算符&逗号运算符&位运算符
    a>b?a:b《--这就是条件运算符
    if(a,b){} 就是逗号运算符
    >>:右移,对于负数来说,偶数除2;奇数先-1,再除2;

  3. 补码
    无符号数,都是正数,必须如此--printf("\u",i);有符号数,如int,0代表+;1代表-
    负数的二进制是补码形式,1开头;补码就是用来表示负数的

posted @   aidengduff  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示
回到顶部