热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言自学笔记

C语言自学笔记1.C语言编程预备知识2.基本的输入输出函数用法3.运算符4.流程控制什么是流程控制流程控制的分类顺序选择循环5.数组为什么需要数组数组的分类一维数组二维数组6.函数


C语言自学笔记

  • 1. C语言编程预备知识
  • 2. 基本的输入输出函数用法
  • 3. 运算符
  • 4. 流程控制
    • 什么是流程控制
    • 流程控制的分类
      • 顺序
      • 选择
      • 循环
  • 5. 数组
    • 为什么需要数组
    • 数组的分类
      • 一维数组
      • 二维数组
  • 6. 函数
  • 7. 变量
  • 8. 指针
  • 9. 结构体
  • 10. 枚举
  • 零散知识笔记




配合视频《郝斌C语言自学教程》


郝斌C语言自学教程程序源码

链接:https://pan.baidu.com/s/1fdUE77WRiqRQPzquDmFODg
提取码:obmv

1. C语言编程预备知识


  1. CPU,内存条,硬盘,显卡,主板,显示器,之间的关系
    例如要打开一部电影,鼠标双击电影,硬盘中的电影数据调入到内存条里面,CPU对内存条中的数据进行处理,如果是图像,就通过显卡在显示器上输出,如果是声音就通过声卡,发出声音;主板将这些模块连接在一起。
  2. Hello World 程序是如何运行起来的
  3. 什么是数据类型
    基本数据类型:
    整数:
      整型:int     4
      长整型:long int  8
      短整型:short int 2
    浮点数 [实数]
       单精度浮点数-- float–4
       双精度浮点数–double–8
    字符:
       char – 1
    复合数据类型:
        结构体
        枚举
        共用体
  4. 什么是变量
    变量的本质就是内存中一段存储空间
  5. 变量为什么必须的初始化
    所谓初始化就是赋值的意思
  6. 常量在C语言中是如何表示的
    在这里插入图片描述
  7. 什么是字节
    字节就是存储数据的单位,并且是硬件所能访问的最小单位
    1 字节 = 8位
    1 K = 1024字节
    1 M = 1024K
    1 G = 1024M

2. 基本的输入输出函数用法

printf() -----将变量的内容输出到显示器上

四种用法


  1. printf("字符串”);
  2. printf(" 输出控制符",输出参数) ;
  3. printf(“输出控制符1 输出控制符2。。。”,输出参数1,输出参数2, 。。。。);;
    输出控制符和输出参数的个数必须一 一对应
  4. printf (”输出控制符 非输出控制符",输出参数) ;
    在这里插入图片描述

为什么需要输出控制符


  1. 01 组成的代码可以表示数据也可以表示指令
  2. 如果01组成的代码表示的是数据的话,那么同样的01代码组合以不同的输出格式输出就会有不
    同的输出结果
    在这里插入图片描述

3. 运算符

在这里插入图片描述
在这里插入图片描述


4. 流程控制


什么是流程控制


  • 代码执行的顺序

流程控制的分类


顺序


选择

定义:某些代码可能执行,也可能不执行,有选择的执行某些代码

分类:

if 1. if 最简单的用法格式:if(表达式)语句功能:如果表达式为真,执行语句如果表达式为假,语句不执行2. if 的范围问题1.if (表达式)语句A; 语句B;解释: if默认只能控制语句A的执行或不执行if无法控制语句B的执行或不执行或者讲:语句B 一定会执行2.if (表达式){语句A;语句B;} 此时if可以控制语句A和语句B由此可见: if默认只能控制一个语句的执行或不执行,如果想控制多个语句的执行或不执行就必须把这些语句用 {} 括起来3. if...else...的用法4. if...else if...else... 的用法格式:if (1)A;else if (2)B;else if (3)C;else D;5. C语言对真假的处理非零是真.零就是假真用1表示假用零表示6. if 举例--求分数的等级7. if 的常见问题解析1> 空语句的问题if(3>2);等价于if(3>2); //这是一一个空语句2>if (表达式1)A;elseB;是正确的if (表达式1) ;A;elseB;是错误的3>if (表达式1)A;else if (表达式2)B;else if (表达式3)C;elseD;即便表达式12都成立,也只会执行A语句,因为如果 表达式1成立,就不会再执行表达式24>if (表达式1)A;else if (表达式2)B;else if (表达式3)C;这样写语法不会出错,但逻辑上有漏洞5>if (表达式1)A;else if (表达式2)B;else if (表达式3)C;else (表达式4) //7行D;这样写是不对的,正确的写法是:要么去掉7行的(表达式4),要么在7行的else后面加if6>if (表达式1)A;else if (表达式2)B;else if (表达式1)C;else(表达式4) ;D;这样写语法不会出错,但逻辑上是错误的else(表达式4) ;D;等价于else(表达式4) ;D;switch

循环

定义:某些代码会重复执行
分类:for1. 格式for(1;2;3)语句A;先执行 1 ,然后执行 22成立标志着此循环成立,开始执行循环,则执行 4,再执行 3, 3 执行完,标志着一次循环结束。是否需要执行下次循环,再次执行 2, 2 成立, 执行4,再执行33 结束,标志着第二次循环结束,(3 执行完标志着一次循环结束)以此类推,直到 2 不成立,则退出循环2. 执行的流程单个for循环的使用多个for循环的嵌套使用(1).for(1;2;3)for(4;5;6) 二A; 三B; 四整体是两个语句,一,二,三是一个语句,四是一个语句说明:先执行 1 ,再执行 22满足后执行:for(4;5;6)A;这个for循环结束之后,然后执行 3 ,一次大循环结束。 然后执行 2, 以此类推, 直到 2 不满足后,退出所有循环,执行 B

举例:

#include
int main()
{int i = 0;int j = 0;for(i = 0; i < 5; i++)for(j = 0; j < 5; j++)printf("第二个循环执行%d次\n",j); printf("**********************************************");return 0;}

输出结果:
在这里插入图片描述

(2).for(1;2;3)for(4;5;6){A;B;}整体是一个语句(3).for(7;8;9)for(1;2;3){A;B;for(4;5;6)C;}整体是一个语句3. 范围问题4. 举例:1 + 2 + 3 + ... + 100# include int main(void){int sum = 0;int i;for (i=1; i<101; ++i){sum = sum + i;}printf("sum = %d\n", sum);return 0;}1 + 1/2 + 1/3 + ... + 1/100# include int main(void){int i;float sum = 0;for (i=1; i<=100; ++i){sum = sum + 1.0/i; //是OK的 推荐使用//sum = sum + (float)(1/i); //这样写是不对的 //也可以这样写: sum = sum + 1 / (float)(i); //不推荐}printf("sum = %f\n", sum); //float必须用%f输出return 0;}

while

在这里插入图片描述

do...while

在这里插入图片描述
在这里插入图片描述

breakcontinuebreakbreak如果用于循环是用来终止循环break如果用于switch, 则是用于终止switchbreak不能直接用于if, 除非if属于循环内部的一个子句例子:for (i=0; i<3; ++i ){if(3>2)break; //break 虽然是if内部的语句,但break终止的确是外部的for循环printf("嘿嘿!\n"); //永远不会输出}在多层循环中,break 只能终止最里面包裹它的那个循环例子:for (i=0; i<3; ++i){for (j=1; j<4; ++j)break; //break 只能终止距离它最近的循环printf ("同志们好!\n");}在多层switch嵌套中,break只 能终止距离它最近的switch例子:int x=1, y=0, a=0, b=0;switch(x) //第一个switch{case 1:switch(y) // 第二个switch{case 0:a++;break; //终止的是第二个switchcase 1:b++;break;}b = 100;break; //终止的是第一个switchcase 2:a++;b++;break;}printf("%d %d\n" ,a, b); //26行最终输出结果是:1 100continue用于跳过本次循环余下的语句,转去判断是否需要执行下次循环例子:1. for(1;2;3).{A;B;continue; //如果执行该语句,则执行完该语句后,会执行语句3, C和D都会被跳过去, C// 和D不会被执行C;D;}2. while (表达式){A;B;continue; //如果执行该语句, 则执行完该语句后,//会执行表达式,C和D都会被跳过去, C和D不会被执行C;D;}

5. 数组


为什么需要数组


  • 为了解决大量同类型数据的存储和使用问题
  • 为了模拟现实世界

数组的分类


一维数组

怎样定义一维数组

为n个变量连续分配存储空间所有的变量数据类型必须相同所有变量所占的字节大小必须相等例子:int a[5];一维数组名不代表数组中所有的元素,一维数组名代表数组第-个元素的地址

有关一维数组的操作

初始化完全初始化int a[5] = {1,2,3,4,5};不完全初始化,未被初始化的元素自动为零int a[5] = {1,2, 3};不初始化,所有元素是垃圾值int a[5];清零int a[5] = {0};错误写法:int a[5];a[5] = {1,2,3,4,5}; //错误只有在定义数组的同时才可以整体赋值, 其他情况下整体赋值都是错误的int a[5] = {1,2,3,4, 5};a[5] = 100; //error 因为没有a[5]这个元素, 最大只有a[4]int a[5] = {1,2,3,4,5};int b[5];如果要把a数组中的值全部复制给b数组错误的写法:b = a;// error正确的写法for (i=0; i<5; ++i)b[i] = a[i];

二维数组

int a[3][4];
总共是12个元素,可以当做3行4列看待,这12个元素的名字依次是
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]
a[i][j]表示第i+1行第j+1列的元素
int a[m][n]; 该二维数组右下角位置的元素只能是a[m-1][n--1]初始化int a[3][4] = {1,2,3,4, 5, 6, 7,8, 9, 10,11,12}int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};操作输出二维数组内容# include int main(void){int a[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10,11,12}};int i, j;//输出数组内容for (i=0; i<3; ++i){ for (j=0; j<4; ++j)printf("%d ", a[i][j]);printf("\n");}return 0;}

多维数组
是否存在多维数组
不存在
因为内存是线性一维的
n维数组可以当做每个元素是n-1维数组的一维数组
比如:
int a[3][4];
该数组是含有3个元素的一维数组
只不过每个元素都可以再分成4个小元素
int a[3][4][5];
该数组是含有3个元素的一维数组
只不过每个元素都是4行5列的二维数组


6. 函数


  • 为什么需要函数
    避免了重复性操作
    有利于程序的模块化
  • 什么叫函数

逻辑上: 能够完成特定功能的独立的代码块
物理上:能够接收数据[当然也可以不接受数据]能够对接受的数据进行处理

  • 如何定义函数
    函数的返回值函数的名字(函数的形参列表)
    {
      函数的执行体
    }
  • 函数定义的本质是详细描述函数之所以能够实现某个特定功能的具体方法
  • return 表达式的含义:

1>终止被调函数,向主调函数返回表达式的值2>如果表达式为空,则只终止函数,不向主调函数返回任何值3> break是用来终止循环和switch的,return是用来终止函数的
例子:void f(){return; //return只用来终止函数,不向主调函数返回任何值}int f()return 10; //第一: 终止函数, 第二: 向主调函数返回10}

  • 函数返回值的类型也称为函数的类型,因为如果函数名前的返回值类型和函数执行体中的return 表达式中表达式的类型不同的话,则最终函数返回值的类型以函数名前的返回值类型为准

例子:int f ()return 10. 5; //因为 函数的返回值类型是 int//所以最终 f 返回的是10而不是10.5

  • 函数的分类
    有参函数和无参函数
    有返回值函数和无返回值函数
    库函数和用户自定函数
    值传递函数和地址传递函数
    普通函数和主函数(main函数)
    一个程序必须有且只能有一一个主函数
    主函数可以调用普通函数普 通函数不能调用主函数
    普通函数可以相互调用
    主函数是程序的入口,也是程序的出口

  • 注意的问题
    函数调用和函数定义的顺序
    如果函数调用写在了函数定义的前面,则必须加函数前置声明

函数前置声明:


  1. 告诉编译器即将可能出现的若干个字母代表的是一个函数
  2. 告诉编译器即将可能出现的若干个字母所代表的函数的形参和返回值的具体情况
  3. 函数声明是一个语句,末尾必须加分号
  4. 对库函数的声明是通过# include <库函数所在的文件的名字. h>来实现的

形参和实参
个数相同
位置一 一对应,数据类型必须相互兼容


7. 变量

按作用域分:全局变量在所有函数外部定义的变量叫全局变量全局变量使用范围: 从定义位置开始到整个程序结束局部变量在一个函数内部定义的变量或者函数的形参都统称为局部变量void f(int i){int j=20;}i和j都属于局部变量局部变量使用范围: 只能在本函数内部使用注意的问题:全局变量和局部变量命名冲突的问题在一个函数内部如果定义的局部变量的名字和全局变量名一样时, 局部变量会屏蔽掉全局变量
按变量的存储方式静态变量自动变量寄存器变量

8. 指针

(见另一篇专门讲指针的文章)
链接: C语言指针详解.


9. 结构体


  • 为什么需要结构体
    为了表示一些复杂的事物,而普通的基本类型无法满足实际要求
  • 什么叫结构体
    把一些基本类型数据组合在一起形成的一个新的复合数据类型,这个叫做结构体
  • 如何定义结构体
    3种方式,推荐使用第一种:

第一种这只是定义了一一个新的数据类型,并没有定义变量
struct Student
{int age;float score;char sex;
};
第二种
struct Student2
{int age;float score;char sex;
}st2 ;
第三种
struct
{int age;float score;char sex ;
} st3;

  • 怎样使用结构体变量
    赋值和初始化
    定义的同时可以整体赋初值
    如果定义完之后,则只能单个的赋初值
  • 如何取出结构体变量中的每一个成员

1. 结构体变量名.成员名
2. 指针变量名->成员名(第二种方式更常用)指针变量名->成员名在计算机内部 会被转化成 (*指针变量名).成员名 的方式来执行所以说这两种方式是等价的
例子:struct Student{int age;float score;char sex;};int main(void){struct Student st = {80, 66.6, &#39;F&#39;}; // 初始化,定义的同时赋初值struct Student * pst = &st; // &st不能改成stpst->age = 88; // 第二种方式st.age = 10; // 第一种方式return 0;}
1.pst->age在计算机内部会被转化成(*pst).age
2.所以pst >age等价于(*pst).age 也等价于st.age
3.我们之所以知道pst->age 等价于st.age, 是因为pst->age 是被转化成了(*pst).age 来执行
4.pst->age的含义:pst 所指向的那个结构体变量中的age 这个成员

结构体变量和结构体指针变量作为函数参数传递的问题
推荐使用结构体指针变量作为函数参数来传递

结构体变量的运算
结构体变量不能相加,不能想减,也不能相互乘除
但结构体变量可以相互赋值

例子:
struct Student
{int age;char sex;char name[100];
}; //分号不能省
struct Student st1, st2;
st1+st2 st1*st2 st1/st2 都是错误的
st1 = st2 或者st2 = st1 都是正确的

10. 枚举

什么是枚举
把一个事物所有可能的取值一 一列举出来

# include
//只定义了一个数据类型,并没有定义变量, 该数据类型的名字是 enum WeekDay
enum WeekDay
{MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay, SunDay
};int main(void)
{//int day; //day定义成int类型不合适enum WeekDay day = SunDay;printf("%d\n", day);return 0;
}

怎样使用枚举

枚举的优缺点
代码更安全
书写麻烦


零散知识笔记

算法: 解题的方法和步骤
如何看懂一个程序,分三步:


  • 流程
  • 每个语句的功能
  • 试数

如何学习一些需要算法的程序【如何掌握一个程序】


  1. 尝试自己去编程解决它
    但要意识到大部分人都是自己无法解决的,这是不要气馁,也不要自卑,如果十五分钟还想不出来,就可以看答案
  2. 如果解决不了,就看答案
    关键是把答案看懂,这个要花很大的精力,也是学习的重点。
  3. 看懂之后尝试自己去修改程序,并且知道修改之后程序的输出结果的含义,
    不建议看懂程序之后就立即自己敲程序
  4. 照着答案去敲
  5. 调试错误
  6. 不看答案,自己独立把答案敲出来
  7. 如果程序实在无法彻底理解,就把它背会,不过无法彻底理解的程序非常少,

强制类型转化


  • 格式:(数据类型)(表达式)
  • 功能:把表达式的值强制转化为前面所执行的数据类型
  • 例子:

(int)(4.5 + 2.2) 最终值是 6
(float)(5) 最终值是 5.000000

浮点数的存错所带来的问题


  • float 和 double 都不能保证可以把所有的实数都准确的保存在计算机中
    例子
    在这里插入图片描述
    因为浮点数无法准确存储,所以就衍生出来两个编程问题:

有一个浮点型变量 x,如何判断 x 的值是否是零if (|x-0.000001| <= 0. 000001)是零else不是零循环中更新的变量不能定义成浮点型

一些琐碎的运算符知识

1. 自增【或者自减】分类:前自增: ++i ;后自增: i++ ;前自增和后自增的异同:相同:最终都使 i 的值加1不同前自增整体表达式的值是i加1之后的值后自增整体表达式的值是i加1之前的值# include int main(void){int i;int j;int k;int m;i = j = 3; //等价于 i = 3; j = 3;k = i++;m = ++j;printf("i = %d, j = %d, k = %d, m = %d\n", i, j, k, m);return 0;}/*在Vc++6.0中的输出结果是:----------------------i = 4, j = 4, k = 3, m = 4----------------------总结:前自增整体表达式的值是i加1之后的值后自增整体表达式的值是i加1之前的值*/

为什么会出现自增?代码更精练自增的速度更快

在这里插入图片描述


  1. 三目运算符
    在这里插入图片描述
  2. 逗号表达式
    格式:
    在这里插入图片描述

推荐阅读
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
author-avatar
mobiledu2502880273
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有