25考研-C语言督学营笔记(自用)

初级阶段(C语言入门)

一、课程导学、编程环境搭建(含安装包)

1.3 Windows的CLion开发环境安装

C语言之父——汤姆逊和丹尼斯里奇

安装MinGW编译器

01910ebc962d4f499114d9f0ee72add2.png

安装CLion开发环境

fe532b68ed654b9d9e064b49685b869b.png

ad93ab8ecb9d4c468b1a76f651235252.png

a2e23577574847f3bd66c79ae814aee9.png

50eb98423fe24c6fb7ae919763a147cf.png

d41daa3b0d96444f8073c563d94512c8.png

4be08b8a5ac34551a2c2be623ed80339.png

a88469f2decf4c23b01655ff38d3870e.png

45bbe1f0640642efaad15c0e0a241fbf.png

点击 New Project 后,弹出下面窗口,图中的项目存储路径与项目名必须是英文的,不可含
有中文,如果自己的用户名是中文的,可以在 D 盘新建一个文件夹,放项目!

d3b07ac136ba442ca617127860e1bf94.png

直接把压缩包b15e471d726845b9867b0cb86aa2f90b.png拖进去

95725f71855c473b89673e18e0e24663.png

0c47a9b867d34a709a15ec124e01ac78.png

921448629693444ea9c4953b424ed046.png

报错

fdda69f971944d0a89d49b7f3ff08770.png

8e551b732c9c4e979c1f57e5eae64ed6.png

1.5向日葵的安装

1.6什么是程序-编译与调试

程序的作用是完成某种计算

新建代码及编译运行

97946d7d71a74e47ac3c336ac5d8adbd.png

fcba2c3600084ed6a33a64f576f56e2e.png

6d5fb626c2524c69b9e62ae6854be0c6.png

f193be2e511541b9994200df3173ea71.png

程序的编译过程及项目位置

8f71eb8489c34a83b08231ae7d191dfa.png

!断点调试

1aceadbebc454549a4fd2158a49a05d5.png

ddc52cd6cfda4661b1c29526c3b63d07.png

30fcd143a5204603b8e020308e324d36.png

de29dd48e2d94dd58d0a5510b19d86a1.png

二、数据的类型、数据的输入输出

2.1数据类型-常量-变量(整型-浮点-字符)

1.数据类型

c55f4a53a5bc47188729742d938e8742.png

b86ed890e61a47108d5ab0dcf9ab64ed.png

2.常量

常量是指在程序运行过程中,其值不发生变化的量。常量又可以分为整型、实型(也称浮点型)、字符型和字符串型。

b3c6d37247b14fb79813deb58a12f8a7.png

3.变量

变量代表内存中具有特定属性的一个存储单元,它用来存放数据,即变量的值。这些值在程序的执行过程中是可以改变的。

77c505c3ca584d11a1e8bee25078e2e6.png

变量的命名规定:C语言规定标识符只能由字母、数字和下画线三种字符组成,并且第一个字符必须为字母或下画线。

e3d1bd14a73949b3becd5fafed013cee.png

4.整型数据

4.1符号常量

627d7e6c96584e7abbbfd284a3d6df4f.png

43aa6698b5d34c5d98924b5a96baf944.png

4.2整型变量

121916d1d9ad45ad8120015bf25a9b30.png

5.浮点型常量

5.1浮点型常量

a38f63e624064deea1bb6129c64d5409.png

d80f67b0ca174c8c8be4e2214edc3cbe.png

5.2浮点型变量

通过float f来定义浮点变量,f占用4个字节的空间

6.字符型数据

6.1字符型常量

用单引号括起来的一个字符是字符型常量,且只能包含一个字符。

916247863706482ab6c0104dad70372b.png

6.2字符数据在内存中的存储形式及其使用方法

7.字符串型常量

c语言中没有字符串变量

字符串常量是由一对双引号括起来的字符序列。

注意:'a'是字符型常量 "a"是字符串型常量,二者是不同的

85eabd4e563245c5b5ee819e0c9b31b1.png

8.ASCII表

b1da5ad2332a49e7adb659d8cdc608cc.png

2.2混合运算及printf的使用

1.强制类型转换

5ce476a72fef46ae960f46e39ee43ffa.png

2.printf函数讲解

printf可以输出各种类型的数据,包括整型、浮点型、字符型、字符串型等。

原理(了解就行):printf函数将这些类型的数据格式化为字符串后,放入标准输出缓冲区,然后将结果显示到屏幕上

printf函数需要头文件声明

a1f38715f1f34079aec8e84a57021dac.png

33e292d4d7b444b39cbc37baf8b9af7c.png

2.3整型常量的不同进制转换

ada0345fde0747b49a80fa7431c3b343.png

十进制转换二进制:除2取余

62289cc7dbe14227afdcb550688cfc77.png

为什么i的值是0x0000007b,显示结果却是7b000000呢?

原因是英特尔的CPU采用了小端方式进行数据存储,因此低位在前、高位在后。

2.4scanf读取标准输入

1.scanf函数的原理

c语言未提供输入/输出关键字,其输入和输出是通过标准函数库来实现的。c语言通过scanf函数读取键盘输入,键盘输入又称为标准输入。当scanf函数读取标准输入时,如果还没有输入任何内容,那么scanf函数会被卡主住(专业术语为阻塞)。

1d799731e5624d40b61e674b0e823899.png

为什么第二个scanf不会阻塞呢?

eea48bfb652d43d29cb0fde97b93e0ab.png

如何避免这个问题呢?

1b46f0af5dc04e52938755804b91c83d.png

59e4c0ad46474874a1aa60c719beef5d.png

为什么这个时候有两次阻塞呢?为什么此时不用fflush?

scanf会阻塞,是因为标准输入缓冲区是空的

整型数和浮点数都会忽略

2.多种数据类型混合输入

5abe681fb58a4f72a9828db900d5cdce.png

150abe9b8161490dbedb8d6d93f8aebb.png

cec35c3c1e094e818b2bf5e400cabfd3.png

三、运算符与表达式

3.1上节课作业讲解

代码路径不能含有中文

printf打印输出不要输出中文,用纯英文,否则会造成乱码

3.2算数运算符和关系运算符
1.运算符分类

2.算术运算符及算术表达式

乘、除、取余运算符的优先级高于加减运算符,取余只能用于整型数

3.关系运算符与关系表达式

c语言中0值代表假,非0值即为真。

3<a<10从左往右运算,输入-2时,3<a的值为0,而0<10,因此输出第一个结果。

正确写法:

4 运算符优先级表

3.3逻辑运算符与赋值运算符,求字节运算符
1.逻辑运算符与逻辑表达式

短路运算

2.赋值运算符

赋值符号左边为左值,右边为右值

错误示范:

3.求字节运算符sizeof

(忘保存了,再写一遍吧,哭死o(╥﹏╥)o)

sizeof不是函数而是运算符 ,用于求常量或变量所占的空间大小

本节课OJ

课时3作业1

#include <stdio.h>
//判断某个年份是不是闰年,如果是闰年,请输出“yes”,否则请输出“no”
int main() {
    int a;
    scanf("%d",&a);
    if(a%4==0&&a%100!=0||a%400==0)
    {
        printf("yes");
    }else{
        printf("no");
    }
    return 0;
}

课时3作业2

#include <stdio.h>
//读取一个整型数,字符,浮点数,分别到变量i,j,k中,然后将i,j,k直接相加并输出,小数点后保留两位小数,不用考虑输入的浮点数的小数部分超过了两位。
int main() {
    int i;
    char j;
    float k;
    scanf("%d %c%f",&i,&j,&k);
    printf("%5.2f",i+j+k);
    return 0;
}

讲解:

%0.2f不限制浮点数输出整体的长度

OJ题读取输入的策略:

第一种情况:读取一行,写一个scanf即可

第二种情况:读取多行,假如三行,for循环3次

注意scanf中不要写\n

记住运算符的优先级,尽量不写太多括号

四、选择、循环

4.2 选择if-else讲解
1.关系表达式与逻辑表达式

算术运算符的优先级高于关系运算符、关系运算符的优先级高于逻辑与和逻辑或运算符

双目运算符:

左操作数+右操作数

单目运算符:

!操作数 逻辑非就是单目运算符

5>3&&8<4-!0

2.if-else语句

加大括号 else不管格式对齐谁,都遵循就近原则

4.3 循环while,for讲解,continue,break讲解
while循环

while()后加分号就会死循环

在循环体内没有让while判断表达式趋近于假的操作,死循环

2.for循环

for和while可以相互转换,for循环不容易忘记初始化

3.continue语句

while语句使用continue时要注意有没有把i++忽略

4break语句

5循环嵌套

4.4 本节课OJ作业

输入一个整型数,判断是否是对称数,如果是,输出yes,否则输出no,不用考虑这个整型数过大,int类型存不下,不用考虑负值;

例如 12321是对称数,输出yes,124421是对称数,输出yes,1231不是对称数,输出no

思路:逆置之后的数字和原来相同

我的答案:

#include <stdio.h>

int main() {
    int a,b=0,c=0,number=0,n;
    scanf("%d",&a);
    n=a;
    for(a;a>0;a=(a-b)/10)
    {
        b=a%10;
        number=c+b;
        c=number*10;
//        printf("a=%d,b=%d,c=%d,number=%d\n",a,b,c,number);
    }
    if(number==n)
    {
        printf("yes");
    }else{
        printf("no");
    }
    return 0;
}

老师的答案:

#include <stdio.h>
//对称数的判断,老师的答案
int main() {
    int a,b=0,backup_a;//可以用backup_a来备份a
    scanf("%d",&a);//读取一个整型数
    backup_a=a;
    while (a)
    {
        b=b*10+a%10;
        a=a/10;
    }
    if(backup_a==b)
    {
        printf("yes");
    }else{
        printf("no");
    }
    return 0;
}

虽然我的答案也AC了,但是我写的有点拧巴,还有问题

问题一:a=(a-b)/10这属实多余,a是整型,计算出来的一定是个整数,不用减b

问题二:循环体里的式子写的不够简洁

利用while或者for循环计算n!的值。提示:n!=1*2*3…*n

#include <stdio.h>

int main() {
    int n,i=1,a=1;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        a=a*i;
    }
    printf("%d",a);
    return 0;
}

某人想将手中的一张面值100元的人民币换成10元、5元、2元和1元面值的票子。要求换正好40张,且每种票子至少一张。问:有几种换法?

#include <stdio.h>

int main() {
   int a,b,c,s,n=0;
   for(a=1;a<=10;a++)
   {
       for(b=1;b<=20;b++)
       {
           for(c=1;c<=50;c++)
           {
               s=a+b+c;
               if(s<40&&10*a+5*b+2*c+40-s==100)
               {
                   n=n+1;
               }
           }
       }
   }
   printf("%d",n);
    return 0;
}

我的问题:

s这个常量完全可以不定义

1元的钞票也得大于1张,2元的钞票最多只能到40

老师的答案:

#include <stdio.h>
int main() {
    int a,b,c,d,count=0;
    for(a=1;a<=10;a++)
    {
        for(b=1;b<=20;b++)
        {
            for(c=1;c<=40;c++)
            {
                for (d=1;d<=40;d++)
                {
                    if(a+b+c+d==40&&10*a+5*b+2*c+d==100)
                    {
                        count=count+1;
                    }
                }

            }
        }
    }
    printf("%d",count);
    return 0;
}

五、一维数组与字符数组

5.2一维数组
数组的定义

借助C语言提供的数组,通过一个符号来访问多个元素。

一维数组的定义格式为:类型说明符 数组名[常量表达式]

例如 int a[10];

一维数组在内存中的存储
5.3数组的访问越界与数组的传递
数组的访问越界

这里我有个疑问,为什么先给j赋值,在内存视图中反而是i的值在前面呢?

操作系统对内存中的每个位置也给予一个编号。

对于windows32位控制台应用程序来说,这个编号的范围是从0x00 00 00 00到0xFF FF FF FF,总计为2的32次方,大小为4G。这些编号称为地址

数组中需要注意的地方:编译器并不检查程序对数组下标的引用是否在数组的合法范围内。

访问越界危害:会改变其他变量的值

常见犯错例子:for循环中

数组的传递

灵活输出数组的值

将关键部分移动到子函数,为什么程序运行的不正确?

那应该怎么解决这个问题?

再定义一个变量length,将数组的长度传递过去

5.4 字符数组与scanf读取字符串
字符数组初始化及传递

初始化的方法:

数组初始化需要注意的细节:

输出字符串

常见错误

输出乱码时,查看字符数组中是否存储了结束符‘\0’

用子函数模拟输出字符串

scanf读取字符串

5.5 gets与puts讲解,strlen-strcmp-strcpy讲解
gets函数与puts函数

str系列字符串操作函数(初试没那么重要,对于机试更重要一些)

strlen的使用及原理

#include <stdio.h>
#include <string.h>
int mystrlen(char c[])
{
    int i=0;
    while(c[i])
    {
        i++;
    }
    return i;
}
int main() {
    int len;
    char e[20];
    char c[20];
    char d[100]="world";
    gets(c);
    puts(c);
    len=strlen(c);//统计字符串的长度
    printf("len=%d\n",len);
    len=mystrlen(c);
    printf("mylen=%d\n",len);
    strcat(c,d);//把d中的字符串拼接到c中,c的位置不可以是字符串
    puts(c);
    strcpy(e,c);//把c中的字符串复制到e中,e的位置不可以是字符串
    puts(e);
    printf("c?d=%d\n", strcmp(c,e));
    //stecmp比较的不是字符串的长度,而是比较字符的ASCII码值
    //前大于后,返回值是正值,小于返回负值,相等返回0
    return 0;
}
本节课OJ作业

作业一:输入N个数(N小于等于100),输出数字2的出现次数;

思路:输入一个整数和一个数组,并且统计2出现的次数

我的代码:

#include <stdio.h>
int main() {
    int n,j=0;
    int a[100];
    scanf("%d",&n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d",&a[i]);
        if(a[i]==2)
            j++;
    }
    printf("%d",j);
    return 0;
}

答案:

#include <stdio.h>
//读取一堆整型数,统计2出现的次数
int main() {
    int element_count;//元素个数
    int arr[100];
    scanf("%d",&element_count);
    for (int i = 0; i < element_count; i++)
    {
        scanf("%d",&arr[i]);//循环读取多个整型数

    }
    //判断整型数组中2出现的次数
    int count=0;
    for(int i = 0; i < element_count; i++)
    {
        if(arr[i]==2)
            count++;
    }
     printf("%d",count);
    return 0;
}

需要注意一些变量名称的设置

作业二:读取一个字符串,字符串可能含有空格,将字符串逆转,原来的字符串与逆转后字符串相同,输出0,原字符串小于逆转后字符串输出-1,大于逆转后字符串输出1。例如输入 hello,逆转后的字符串为 olleh,因为hello 小于 olleh,所以输出-1

我的代码:

#include <stdio.h>
#include <string.h>
//解决三个问题:一、逆转 二、比较 三、输出
int main() {
    int len,i,result;
    char c[30];
    char d[30];
    gets(c);
    len=strlen(c);
    for(i=0;i<len;i++) {
        d[len - i - 1] = c[i];
    }
    result= strcmp(c,d);
    if(result>0)
        printf("%d\n",1);
    else if (result<0)
        printf("%d\n",-1);
    else
        printf("%d\n",0);
    return 0;
}

答案:

#include <string.h>
//字符串翻转,翻转后比较与原字符串是否相等
//使用增量编写法
int main() {
    int len,i,j,result;
    char c[100];//原字符串
    char d[100]={0};//翻转后的,初始化的目的就是让d有结束符
    gets(c);
    for(i=0,j= strlen(c)-1;i< strlen(c);i++,j--) {
        d[j] = c[i];
    }
    result= strcmp(c,d);
    if(result>0)
        printf("%d\n",1);
    else if (result<0)
        printf("%d\n",-1);
    else
        printf("%d\n",0);
    return 0;
}

注意:

一、windows下使用VS的集成开发环境不能使用gets

可以用

char c[100];

fgets(c,sizeof(c),stidin)

clion使用c99标准

二、注意数组d的要有结束符,解决方法就是初始化d

六、指针

6.2指针的本质(间接访问原理)

指针的定义

取地址操作符&与取值操作符*,指针本质

定义指针变量

指针变量所占用的空间大小

需要注意的4点

6.3指针的传递使用场景

为什么i的值不会改变?

函数调用不会改变变量的值,那怎么样才能改变变量的值呢?

6.4指针的偏移使用场景

指针的偏移

p存储着数组的起始地址0x61fe20,那为什么p+1是0x61fe24呢?

float *p也是偏移4个字节

指针与一维数组

6.5指针与malloc动态内存申请,栈与堆的差异

指针与动态内存申请(有很大概率会用到,非常重要)

空间不用时,要释放申请的空间

指针本身的大小和其指向空间的大小是两码事,指针本身的大小永远都是8字节。

栈空间与堆空间差异(了解)

堆的效率要比栈低得多,但是栈不能动态使用

OJ作业

作业一:输入一个整型数,存入变量i,通过子函数change把主函数的变量i除2,然后打印i,例如如果输入的为10,打印出5,如果输入的为7,打印出3

我的答案:

#include <stdio.h>
void change(int *j)
{
    *j=*j/2;
}
int main() {
    int i;
    scanf("%d",&i);
    change(&i);//传递变量i的地址
    printf("%d\n",i);
    return 0;
}

 老师的答案:

#include <stdio.h>
//在子函数中改变main函数中某个变量的值
void change(int *j)//j=&i
{
    *j=*j/2;
}
int main() {
    int i;
    int *p=&i;//如果定义一个指针变量,没有初始化,就是空的藏宝图
    scanf("%d",p);
    change(p);//传递变量i的地址
    printf("%d\n",*p);
    return 0;
}

作业二:输入一个整型数,然后申请对应大小空间内存,然后读取一个字符串(测试用例的字符串中含有空格),字符串的输入长度小于最初输入的整型数大小,最后输出输入的字符串即可(无需考虑输入的字符串过长,超过了内存大小);

我的答案:

#include <stdio.h>
void change(int *j)
{
    *j=*j/2;
}
int main() {
    int i;
    scanf("%d",&i);
    change(&i);//传递变量i的地址
    printf("%d\n",i);
    return 0;
}

老师的答案:

#include <stdio.h>
#include <stdlib.h>
//malloc的使用
int main() {
    int n;//代表申请空间的大小
    scanf("%d",&n);//读取
    char c;
    scanf("%c",&c);
    //注意在scanf和gets中间使用scanf("%c",&c),清除标准输入缓冲区中的\n
    char *p;
    p=(char *)malloc(n); //申请n个字节大小的空间,强制类型转换为char*
    fgets(p,n,stdin);//gets(p);容易产生访问越界所以被去掉了
    puts(p);
    return 0;
}

七、函数

八、结构体及C++引用讲解

8.2结构体-结构体对齐-结构体数组

结构体

#include <stdio.h>

struct student{
    int num;
    char name[20];
    char sex;
    int age;
    float score;
    char addr[30];
};//结构体类型声明,注意最后一定要加分号

int main() {
    struct student s={1001,"lele",'M',20,85.4,"Shenzhen"};
    //定义及初始化
    //变量名不要和结构体类型名重名
    struct student sarr[3];//定义一个结构体数组变量
    int i;
    //结构体输出必须单独去访问内部的每个成员
    s.num=1003;
    printf("%d %s %c %d %f %s\n",s.num,s.name,s.sex,s.age,s.score,s.addr);
    printf("--------------------------------------\n");
//    scanf("%d%s %c%d%f%s",&s.num,s.name,&s.sex,&s.age,&s.score,s.addr);
    for(i=0;i<3;i++)
    {
        scanf("%d%s %c%d%f%s",&sarr[i].num,sarr[i].name,&sarr[i].sex,&sarr[i].age,&sarr[i].score,sarr[i].addr);
    }
    for(i=0;i<3;i++)//结构体数组的输出
    {
        printf("%d %s %c %d %f %s\n",sarr[i].num,sarr[i].name,sarr[i].sex,sarr[i].age,sarr[i].score,sarr[i].addr);
    }

    return 0;
}
结构体对齐

结构体大小必须是其最大成员(不包括数组)的整数倍

为什么要对齐呢?就是为了cpu高效的去取内存上的数据

#include <stdio.h>

struct student_type1{
    double score;//double是一种浮点类型,8个字节,浮点分为float和double,记住有这两种即可
    short age;//short 是整型,占2个字节
};

struct student_type2{
    double score;
    int height;//如果两个小存储之和是小于最大长度8,那么它们就结合在一起
    short age;
};

struct student_type3{
    int height;
    char sex;
    short age;
};
//结构体对齐
int main() {
    struct student_type1 s1;
    struct student_type2 s2={1,2,3};
    struct student_type3 s3;
    printf("s1 size=%d\n",sizeof(s1));
    printf("s2 size=%d\n",sizeof(s2));
    printf("s3 size=%d\n",sizeof(s3));
    return 0;
}

8.3结构体指针与typedef的使用

结构体指针

一个结构体变量的指针就是该变量所占据的内存段的起始地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student{
    int num;
    char name[20];
    char sex;
};
//结构体指针的练习
int main() {
    struct student s={1001,"wangle",'M'};
    struct student sarr[3]={1001,"lilei",'M',1005,"zhangsan",'M',1007,"lili",'F'};
    struct student *p;//定义了一个结构体指针变量
    p=&s;
    printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);//方式1访问通过结构体指针去访问成员
    printf("%d %s %c\n",p->num,p->name,p->sex);//方式2访问通过结构体指针去访问成员,用这种
    p=sarr;
    printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);//方式1访问通过结构体指针去访问成员
    printf("%d %s %c\n",p->num,p->name,p->sex);//方式2访问通过结构体指针去访问成员,用这种
    printf("------------------------------\n");
    p=p+1;
    printf("%d %s %c\n",(*p).num,(*p).name,(*p).sex);//方式1访问通过结构体指针去访问成员
    printf("%d %s %c\n",p->num,p->name,p->sex);//方式2访问通过结构体指针去访问成员,用这种
    //下面给结构体指针p通过malloc申请空间,并对其成员赋值,再访问
    //(struct student*)强制类型转换
    p=(struct student*)malloc(sizeof(struct student));
    p->num=100;
    p->sex='M';
    strcpy(p->name,"longge");
    printf("------------------------------\n");
    printf("%d %s %c\n",p->num,p->name,p->sex);
    return 0;
}
typedef的使用
#include <stdio.h>

//stu 等价于 struct student,pstu等价于struct student*
typedef struct student{
    int num;
    char name[20];
    char sex;
}stu,*pstu;

typedef int INGETER;//特定地方使用
//typedef的使用,typedef起别名
int main() {
    //struct student s={0};
    stu s={1001,"wangle",'M'};
    stu *p=&s;//定义了一个结构体指针变量
    pstu p1=&s;//定义了一个结构体指针变量
    INGETER num=10;
    printf("num=%d,p->num=%d\n",num,p->num);
    return 0;
}

8.4c++引用的讲解

c++的引用讲解

#include <stdio.h>

//当你在子函数中要修改主函数中变量的值,就用引用,不需要修改,就不用
void modify_num(int &b)//形参中写&,要称为引用
{
    b=b+1;
}
//C++的引用的讲解
//在子函数内修改主函数的普通变量的值
int main() {
    int a=10;
    modify_num(a);
    printf("after modify_num a=%d\n",a);
    return 0;
}
#include <stdio.h>

void modify_pointer(int *&p,int *q)//引用必须和变量名紧邻
{
    p=q;
}
//子函数内修改主函数的一级指针变量
int main() {
    int *p=NULL;
    int i=10;
    int *q=&i;
    modify_pointer(p,q);
    printf("after modify_pointer *p=%d\n",*p);
    return 0;//进程已结束,退出代码为 -1073741819 ,不为0,那么代表进程异常结束
}

c++的布尔类型

8.5本节课OJ

  • 35
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值