找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2432|回复: 4
收起左侧

谭浩强C语言学习记录(上)

[复制链接]
ID:763998 发表于 2021-9-3 23:15 | 显示全部楼层 |阅读模式
《上》2021-09-03
《C程序设计---谭浩强》
    1.1991年编写的
    2.C神器
《C目录》
    1.程序设计与C语言
    2.算法--程序的灵魂
    3.最简单的程序设计--顺序程序设计
    4.选择程序设计
    5.循环程序设计
    6.利用数组批量处理数据
    7.使用函数实现模块设计
    8.善用指针
    9.用户建立自己的数据类型
    10.文件的输入输出
《为什么学程序设计》
    1.理解计算机如何工作
    2.理解计算机工作原理
    3.应用计算机解决问题
《为什么学C》
    1.功能丰富
    2.表达能力强
    3.使用灵活方便
    4.应用面广
    5.目标程序效率高
    6.可移植性好
    7.既有高级语言的优点,又有低级语言的许多特点
    8.既适于编写系统软件、又能方便地用来编写应用软件
《C建议》
    1.大学生毕业前一定要学好C,C语言是当前程序员的共同语言
    2.在编写底层设备驱动和内嵌应用程序应用广泛
《如何学习C》
    1.着眼于培养能力
        (1)分析问题的能力
        (2)构造算法能力
        (3)编程能力
        (4)调试程序能力
    2.重视实践环节
        (1)C是一门应用课程、而非纯理论课程
        (2)学得好环不是看你知不知道,而是看你会不会干
        (3)打好基础很重要,为学习更高级的知识做准备
    3.构造算法
        (1)算法是程序的灵魂
        (2)积累算法是必须的
《什么是计算机程序》
    1.一组计算能识别和执行的指令
    2.计算机的一切操作都是由程序控制
    3.计算机的本质是程序的机器
《什么是计算机语言》
    1.用于人与计算机交流的语言
    2.计算机基于二进制工作,只能识别二进制----机器语言
    3.符号语言、便于记忆,使用---又称汇编语言
        汇编---将符号语言装换成机器语言
        汇编语言与机器语言完全依赖具体的机器特性--低级语言
    4.不依赖具体的机器的语言---高级语言--C系统描述语言
《C标准》
    1.ANSI C和C89和C90是同一个标准
    2.C99--对C89的扩充
    3.TC1\TC2--技术修正
    4.嵌入式系统编程以C89为准
《C语言的特点》
    1.语言简洁紧凑、使用灵活方便
    2.运算符、数据类型丰富
    3.结构化控制语句
    4.语言限制不太严格、程序设计自由度大
    5.允许直接访问物理地址、能进行位操作、能实现汇编大部分功能
    6.可移植性好、生成目标代码质量高、程序执行效率高
《C语言的有多少个关键字》
    C89 --32个
    C99 --37个
《C语言的9种流程控制语句》
    1.选择
        if
        switch
    2.循环
        while
        do while
        for
    3.跳转
        continue
        break
        return
        goto
《C语言的34种运算符》
    优先级        运算符        含义                    结合方向
    1            ()        圆括号                    自左向右
    1             []            下标运算符                自左向右
    1             ->            指向结构体成员运算符    自左向右
    1             .            结构体成员运算符        自左向右
    2             !            逻辑非运算符            自右向左
    2             ~            按位取反运算符            自右向左
    2             ++            自增运算符                自右向左
    2             --            自减运算符                自右向左
    2             -            负号运算                自右向左
    2          (类型)        类型转换运算符            自右向左
    2             *            指针运算符                自右向左
    2             &            取地址运算符            自右向左
    2           sizeof        长度运算符                自右向左
    3             *            乘法运算符                自左向右
    3             /            除法运算符                自左向右
    3             %            求余运算符                自左向右
    4             +            加法运算符                自左向右
    4             -            减法运算符                自左向右
    5             <<         左移运算符                自左向右
    5             >>         右移运算符                自左向右   
    6       <、<=、>、>=    关系运算符                自左向右
    7               ==            等于运算符                自左向右
    7            !=            不等于运算符            自左向右
    8             &            按位与运算符            自左向右
    9             ^            按位异或运算符            自左向右
    10             |            按位或运算符            自左向右
    11             &&            逻辑与运算符            自左向右
    12             ||            逻辑或运算符            自左向右
    13             ?:            条件运算符                自右向左
    14         =、+=、-=、    赋值运算符                自右向左
    14         *=、/=、%=        赋值运算符                自右向左
    14         <<=、>>=        赋值运算符                自右向左
    14         &=、^=、|=        赋值运算符                自右向左
    15              ,            逗号运算符                自左向右
   
记忆口诀:
    密不可分
    四对半
    四则
    大于小于号多的
    位高于逻辑,与高于或,异或夹中间
    条件
    赋值--四则与位(除了按位取反没有复合运算)
    逗号
    结合方向:
        单目、三目与赋值从右向左结合
        其他的都是从左到右
《C语言的32关键字---ASIN C/C89/C90》
    数据类型关键字(20)
        基本数据类型关键字
        1.void
        2.char
        3.int
        4.float
        5.double
        类型修饰关键字
        1.short
        2.long
        3.signed
        4.unsigned
        复杂类型关键字
        1.struct
        2.union
        3.enum
        4.typedef
        5.sizeof
        存储类型关键字
        1.auto
        2.static
        3.register
        4.extern
        5.const
        6.volatile
    流程控制关键字(12)
        分支结构
        1.if
        2.else
        3.switch
        4.case
        5.default
        循环结构
        1.while
        2.do
        3.for
        跳转结构
        1.continue
        2.break
        3.return
        4.goto
    《C99新增的5个关键字》
        1.inline
        2.restric
        3.Bool
        4._Complex
        5._Imaginary
《C语言注释》
    1.注释是给人看的
    2.在预处理时将注释替换为空格,所以不产生目标代码
    3.单行注释是C99标准的--//
    4.多行注释不可嵌套注释--/**/
        错误代码:
            #include<stdio.h>
            int main(void)
            {
                /*
                /*
                */
                */---报错
                return 0;
            }
    5.在字符串中的//与/**/不作为注释的开始
        #include<stdio.h>
        int main(void)
        {
            printf("/*你好*/\n");--/*你好*/
            printf("//我好");--//我好
            return 0;
        }
《C语言程序结构》
    1.一个程序由一个或多个源文件组成
    2.函数是C程序的主要组成部分
    3.程序总是从main函数开始执行
    4.C语言本身不提供输入输出语句
    5.程序应当包含注释
《程序设计的任务》
    1.问题分析
    2.设计算法
    3.编写程序
    4.对源程序进行编辑、编译、链接
    5.运行程序,分析结果
    6.编写程序文档
《算法的初探》
    1.为解决某一问题采取的方法和步骤
    2.数值运算算法、非数值运算算法(主要的)
    3.采用方法简单、运算步骤少的
    4.算法的目的是求解,解就是输出,没用输出的算法是没有意义的
    5.设计算法、实现算法
《算法的特性》
    1.有穷性
    2.确定性
    3.有零个输入或多个输入
    4.有一个输出或多个输出
    5.有效性
《怎样表示一个算法》
    1.自然语言
    2.传统流程图
    3.结构化流程
    4.N-S流程图
    5.伪代码
《结构化程序的设计》
    分而治之的思想
    1.自顶向下
    2.逐步细化
    3.模块化设计
    4.结构化编码
《编写C程序必须具备的》
    1.心中要有算法
    2.掌握C语言的语法
《数据的表现形式》
    1.常量--在程序运行过程中,其值不能被改变的量
        整型常量
            十进制
            八进制
            十六进制
            二进制
        实型常量
            十进制小数形式
            指数形式
                E或e--以10为底的指数
                E或e--前必须有数,后必须为整数
        字符常量
            普通字符--单引号引起来的一个字符
            转义字符--以\开头的字符序列
                把\后面的字符转换成另外的意思
                    \n---n不是字母,n表示换行
                    \ooo--八进制表示      最大\177
                    \xoo--十六进制表示     最大\7F
                        因为ASCII表示的数的范围0~127
            字符串常量--用双引号引起来的若干字符
            符号常量--使用#define指定定义的
                好处:
                    1.见名知意
                    2.一改全改
        符号常量与常变量的理解
            1.符号常量是一个符号、没有地址,在预编译后这个符号就不见了
            2.常变量量--有地址、在编译后存在
            3.符号常量才是真正的常量,因为没有地址,无法通过指针修改
                #include<stdio.h>
                #define PI 3.14
                const int a=1;
                int main(void)
                {
                    
                    printf("%x",&a);//0x404004
                    //printf("%d",&PI);//报错
                    return 0;
                }
    2.变量---一个有名字的、具有特定属性的一个存储单元,在程序运行过程中,可以被改变
        C89规定:变量必须先定义,后使用
        C99规定:变量可以在函数或复合语句中定义
            变量名:
                代表一个存储地址
                通过变量写入或获取值的本质:
                    通过变量名找到相应内存地址
                    通过地址确定相应存储单元
                    通过相应存储单元中获取值
            变量值
            存储单元
    3.标识符
        1.用于对象命名的有效字符序列
            数字、字母、下划线
            不能以数字开头
            不能是关键字
《数据的类型》
    1.对数据分配存储单元的安排
        数据的长度
        数据的存储形式
    2.结构图
    数据类型
        基本数据类型
            整型型
                基本整型 int
                短整型 short int
                长整型 long int
                字符型 char
                C99增加的:
                    *双长整型 long long int
                    *布尔 bool
            浮点型
                单精度浮点型 float
                双精度浮点型 double
                复数浮点型 float_complex,double_comple,long long_comple
        派生数据类型
            指针类型 *
            数组类型 []
            结构体类型 struct
            共用体类型 union
            函数类型
        枚举类型 enum
        空类型 void
《整型数据》   
    1.数据的存储是以补码形式存储在内存中
    2.C标准并没有具体规定各种数据类型所占用的存储空间,有各编译系统自行决定
    3.C标准值要求long类型长度不不短于int类型,short类型不长与int类型
        sizeoof(short)<=sizeof(int)<=sizeof(long)<=sizeof(long long)
        通常规定short占16位,long占32位,int的可以是16位,也可以是32位
            int 在16或8位系统中     占16位
            int 在32或64位系统中     占32位
    无符号---表示不能表示负数,只能表示0和正数
    若未指定signed或unsigned,则默认使signed
    只有整型数据可以加signed或unsigned,实型不能加
    字符是按其代码(整数)形式存储的,因此C99把字符数据作为整型类型中的一种
    所以字符1与整数1不是一个概念
《浮点型数据》
    1.用来表示小数
    2.实数以指数形式存储
        一个小数使用指数形式表示不止有一种形式
        只要在小数点移动的同时改变指数的值,就能保证小数的值不变
        实数的指数形式--浮点数
    3.规范指数形式
        小数点前的数字为0,小数点后的数字不为0
            3.14159  ----- 0.3.14159E1
    4.浮点型  --小数部分   ---指数部分
        小数位数越多,精度越高,表示范围越小
        小数位数越少,精度越低,表示范围越大
        
        类型      有效位数
        float        6
        double        15
        
    整数默认使int 浮点数默认是double
《运算符》
    1. /
        两个实数相除结果是双精度实数
        两个整数相除结果是整数
        有负数的除法向零取整
        #include<stdio.h>
        int main(void)
        {
            printf("%d\n",sizeof(5.0/3.0));//8--双精度
            printf("%d\n",5/3);//1
            printf("%d\n",-5/3);//-1
            return 0;
        }
    2. %
        要求参加的运算对象为整数
        实数没有求余的说法
        除%外的运算符的操作数可以是任意数据类型
        #include<stdio.h>
        int main(void)
        {

            printf("%d\n",5%3);//2
            printf("%d\n",-5%3);//-2
            printf("%d\n",5.0%3);//报错
            return 0;
        }   
    3.字符
        字符是整数代码形式存储的---ASCII
        输出形式有两种
            整数输出
            字符输出
《语句》
    1.表达式---运算符+操作数
    2.语句---表达式+分号
    3.空语句--没有表达式,只有分号
    4.复合语句--用花括号括起来的语句--又称语句块
   
        #include<stdio.h>
        int main(void)
        {
            int a=0,b=0;
            a+b//表达式 ---报错
            a+b;//语句
            ; //空语句
            {
                a+b;//复合语句
            }
            return 0;
        }
    5.左值--出现在赋值运算符的左侧
    6.右值--出现在赋值运算符的右侧
        凡是是左值都可以作为右值
            变量是左值--可被赋值改变
            常量是右值--不可被赋值改变
            表达是右值--不可被赋值改变
        #include<stdio.h>
        #define N 10
        int main(void)
        {
            int a=0,b=0;
            a=1;//左值可通过赋值改变
            a=b;//左值可以作为右值
            (a+b)=3*4;//报错 (a+b)是表达式,是右值,不能作为左值,不能通过赋值改变
            N=10;//报错 N是常量,是右值,不能左值,不能通过赋值改变
            printf("%d",a);
        }
《有关输入输出的概念》
    1.输入输出是以计算机为主体而言
    2.C语言本身不提供输入输出语句,输入输出操作是由C标准库函数来实现
        好处:
            使C编译系统简单精炼
            在编译阶段避免处理有关硬件有关问题、提高可移植性
            库函数在链接阶段与源目标文件连接,生成可执行文件
    3.标准输入输出函数
        putchar---输出字符
            输出一个字符
                显示字符
                控制字符
        getchar---输入字符
                显示字符
                控制字符
            说明:
                1.在键盘上输入信息时,并不是在键盘上敲一个字符就马上送到计算机中去的
                2.这些字符存储在键盘的缓冲器中,只有按下Enter键才把这些字符输入到计算机中去
                3.最后按顺序分别赋值给相应的变量
        printf----格式化输出
            格式控制
                %d--有符号的十进制整数
                %c--输出一个字符
                %s--输出字符串
                %f--输出实数
                    %f---整数部分全部输出,小数部分输出6位
                    %m.nf
                        m--数据的宽度
                        n--输出的小数位数
                        默认右对齐
                            数据在右,左端补空格
                    %-m.n
                        m--输出的列数
                        n--输出的小数位数
                        -  左对齐
                            数据在左,右端补空格
                    #include<stdio.h>
                    int main(void)
                    {
                        int a=0;
                        char c=65;
                        char s[10]="nihao";
                        float f = 123.456;
                        printf("%d\n",a);     //0
                        printf("%c\n",c);      //A
                        printf("%s\n",s);      //nihao
                        printf("%f\n",f);      //123.456001---默认6位有效位
                        printf("%20.4f\n",f); //            123.4560---默认右对齐
                        printf("%-20.4f\n",f);//123.4560---加负号,左对齐
                    }
                %e--指数形式输出实数
                    小部分占6位
                    指数部分占5位
                        e占1列
                        指数符号占1列
                        指数占3列
                    #include<stdio.h>
                    int main(void)
                    {
                        float f = 123.456;
                        float f1 = 1234.4456;
                        printf("%e\n",f);//1.234560e+002
                        printf("%e\n",f1);//1.234446e+003
                    }
                其他不常用
                    %i--与%d相同--按十进制整数数据实际长度输出
                    %o--以八进制整数形式输出
                    %x--以十六进制整数形式输出
                    %u--以无符号十进制整数输出
                    %g--输出浮点数、选择%f\%e输出宽度较短的格式输出,不输出没有意义的0
                格式控制的一般形式
                    % 附加字符 格式字符
                        附加字符   
                            l--长整型整数
                            m--数据的最小宽度
                            n--
                                实数--输出n个小数
                                字符串--截取字符的个数
                            -   输出的数字或字符在域内向左靠
                    #include<stdio.h>
                    int main(void)
                    {
                        char s[20]="hello word!";
                        printf("%s\n",s);        //hello word!
                        printf("%10.7s\n",s);   //   hello w
                        printf("%-10.7s\n",s);  //hello w
                    }
                输出列表
            说明:
                1.printf输出时,输出对象的类型要跟格式类型一致,否则会出现错误
                2.除了X、E、G外,其他格式字符必须使用小写
                3.格式控制字符串内可以包含转义字符
                4.想输出%,需要写两个
            总结:
                格式控制字符串=[格式声明]+[转义字符]+[普通字符]
                格式声明=%+[附加字符]+格式字符
                附加字符={l,m,n,-}
                格式字符={d,i,o,x,X,u,c,s,f,e,E,g,G}
        scanf-----格式化输入
            格式控制--同printf
            地址列表--地址
        gets------输入字符串
            #include<stdio.h>
            int main(void)
            {
                char s[20];//缓冲区
                printf("%s",gets(s));//打印获取到的数据
            }
        puts------输出字符串
            #include<stdio.h>
            int main(void)
            {
                char s[30]="我在景德镇等你";//缓冲区
                puts(s);//打印缓冲区的数据 并自动换行
            }
            #include<stdio.h>
            int main(void)
            {
                char s[20]="我说桥边姑娘";//缓冲区
                puts(gets(s));//覆盖原来的数据,打印获取到的数据 并自动换行
            }
《流程控制》
    if与switch的理解
        switch使用同一个条件去匹配,每个匹配项共用这个条件,可以对这个条件进修改,到达状态转换的目的
        if的多条件更多描述区间,switch描述的是某一点
    if else 与 ?:的关系
        等价
        使用?:只需要一条语句就能达到同样的效果
        使用?:在不使用关键字的情况下就能达到同样的效果
    闰年的理解
        1.能被4整除,不能被100整除
        2.能被400整数 如:2000年是闰年 1900不是闰年
    为什么需要循环?
        程序处理的问题需要重复处理
    continue 与 break
        continue 结束本次循环
        break    结束整个循环
《数组》   
    1.反映数据的特点与内在联系
    2.下标从零开始
    长度的理解
        程序运行过程中,不允许对同一数组的长度进行改变--C89
            #include<stdio.h>
            int main(void)
            {
                int len;
                scanf("%d",&len);//获取长度
                int arr[len];//作为数组的长度
               
                for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循环获取值
                scanf("%d",&arr[ i]);
               
                for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循环显示
                printf(" %d ",arr[ i]);
                return 0;
            }

            #include<stdio.h>
            int main(void)
            {
                int len;
                for(int i=0;i<5;i++) //循环获取长度  
                scanf("%d",&len);
                int arr[len];//作为数组的长度--最后一个起作用
               
                for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循环获取值
                scanf("%d",&arr[ i]);
               
                for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循环显示
                printf(" %d ",arr[ i]);
                return 0;
            }
        C99支持变长数组

    Fibonacci数列---斐波那契数列
        1 1 2 3 5 8 13 21 35 ....
        1.从第三项开始,每一项等于前两项之和

    冒泡算法--三段法理解
        1.如果有2个数,需要比较2-1趟
        2.如果有3个数,需要比较3-1趟
        ....
        3.如果有n个数,需要比较n-1趟
        
        1.第1趟需要比较n-1次
        2.第2趟需要比较n-2次
        .....
        3.第j趟需要比较n-j次
    算法实现:
        #include<stdio.h>
        int main(void)
        {
            puts("请输入要比较的个数:");
            int len;
            scanf("%d",&len);
            int arr[len];
            /* 循环获取用户的输入 */
            for(int i=0;i<sizeof(arr)/sizeof(int);i++)
            scanf("%d",&arr[ i]);
            /* 排序之前 */
            puts("排序之前") ;
            for(int i=0;i<sizeof(arr)/sizeof(int);i++)
            printf(" %d ",arr[ i]);
            puts("") ;
            /* 冒泡算法实现 */
            for(int i=0;i<len-1;i++)
            for(int j=0;j<len-1-i;j++)
            {
                if(arr[j+1]<arr[j])
                {
                    int temp;//放最大的数
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;//把最大的数交换到最后
                }
            }
            /* 排序之后 */
            puts("排序之后") ;
            for(int i=0;i<sizeof(arr)/sizeof(int);i++)
            printf(" %d ",arr[ i]);
        }
《二维数组》
    二维数组可以看成一个特殊的一维数组,这个特殊的数组的元素是一个个一维数组
    内存存储--按行存储
        int[3][4];
        存储结构:
            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[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]
            
    初始化时,行号可以省略,列号不可省略--看逻辑结构理解
《字符数组》   
    字符串的有效长度与字符数组的长度不是一个概念
        字符串:双引号引起来的字符,以'\0'为结束标志
        字符串有效长度:'\0'之前的有效字符个数
        字符数组:存放字符的数组
        字符数组的长度:定义时写的大小
        因为C语言没有字符串的数据类型,所以使用字符数组来表示
        由上可知,字符数组的长度比字符串的长度大
    字符串的输入输出
        %s--一次性输入\输出
            scanf("%s",字符数组名);
            printf("%s",字符数组名);
            #include<stdio.h>
            int main(void)
            {
                char arr[30];
                scanf("%s",arr);
                printf("%s",arr);
            }
《字符串处理函数》
    puts(字符数组);
    gets(字符数组);
        #include<stdio.h>
        int main(void)
        {
            char arr[10];
            puts(gets(arr));//获取直接输出
        }
        #include<stdio.h>
        int main(void)
        {
            char arr[10];
            char *a;
            a=gets(arr);//返回值为char *
            puts(a);
        }
        #include<stdio.h>
        int main(void)
        {
            char arr[10];
            char *a;
            a=gets(arr);//返回值为char *
            *a=65;//把第一位改为A
            puts(a);
        }
    strcat(字符数组1,字符数组2);
        将字符数组2连接到字符数组1的后面
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                char arr1[20]="hello";//被连接的数组要足够大,否则会有意想不到的后果
                char arr2[10]="word!";
                puts(arr1);//连接之前 hello
                strcat(arr1,arr2);
                puts(arr1);//连接之后 helloword!
            }

    strcpy(字符数组1,字符数组2);
        将字符数组2复制到字符数组1的中去
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                char arr1[6]="hello";
                char arr2[10]="word!";
                puts(arr1);//复制之前 hello
                strcpy(arr1,arr2);
                puts(arr1);//复制之后 word!  ---完全覆盖原来的字符
               
            }
    strcmp(字符数组1,字符数组2);
        将字符数组2与字符数组1比较
        根据ASCII表进行比较,直到出现不同的字符或遇到'\0'为止
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                int result;
                char arr1[6]="hello";
                char arr2[10]="aord!";
                result=strcmp(arr1,arr2);
                printf("%d",result) ;//1 字符串1>字符串2 正数
               
            }
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                int result;
                char arr1[6]="hello";
                char arr2[10]="word!";
                result=strcmp(arr1,arr2);
                printf("%d",result) ;//1 字符串1<字符串2 负数
               
            }
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                int result;
                char arr1[6]="hello";
                char arr2[10]="hello";
                result=strcmp(arr1,arr2);
                printf("%d",result) ;//0  字符串1等于字符串2  0
               
            }
    strlen(字符数组);
        求字符的长度
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                int result;
                char arr[]="hello";
                result=strlen(arr);
                printf("%d\n",result) ;//5 字符串的有效长度
                printf("%d",sizeof(arr)/sizeof(char));//6 字符数组的长度
            }
    strlwr(字符数组);
        转为小写的函数
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                char arr[]="WORD";
                char *a;
                a=strlwr(arr);//返回char *类型转小写
                printf("%s\n",a);//word
            }
    strupr(字符数组);
        转为大写的函数
            #include<stdio.h>
            #include<string.h>//需要引入字符处理函数头文件
            int main(void)
            {
                char arr[]="hello";
                char *a;
                a=strupr(arr);//返回char *类型转大写
                printf("%s\n",a); //HELLO
            }
《统计单词个数》
    1.一个空格对应一个新词
        #include<stdio.h>
        #include<string.h>//需要引入字符处理函数头文件
        int main(void)
        {
            char string[100];//存放单词的容器
            int word=0;//统计单词标志
            int flag=0;//判断是否以空格开头标志
            int number=0;//计数器
            char c;//存放每个字符
            gets(string);//获取数据
            for(int i=0;(c=string[ i])!='\0';i++)
            {
                if(string[0]!=' ')//不是以空格开始
                {
                    flag=1;
                    if(c==' ')//一个空格对应一个单词
                    {
                        word=1;   
                    }
                    else
                    if(word==1)
                    {
                        word=0;
                        number++;
                    }
                }
                else//以空格开始
                {
                    if(c==' ')
                    {
                        word=1;   
                    }
                    else
                    if(word==1)
                    {
                        word=0;
                        number++;
                    }
                }
            }
            if(flag)
            printf("%d\n",number+1);//给第一个单词加个空格
            else
             printf("%d\n",number);
        }
《函数》
    1.让代码可重用
    2.使程序便于维护和阅读
    3.模块化设计的需要
    函数包括两个部分
        函数首部
            函数的返回值
            函数名
            参数列表
        函数体
            具体实现
    空函数的作用
        提高程序的扩展性
    实参与形参
        实参:在调用函数时传递的参数
        形参:在定义函数时写的参数
    调用函数的过程
        1.实参把数据传给形参
        2.形参把数据转入函数内部进行处理
    函数的类型决定返回值类型
    函数的原型=函数的首部
    函数的声明=函数的首部+分号
    函数的递归调用--函数直接或间接的调用自己
《求0~15内的阶乘》
        #include<stdio.h>
        int dg(int number);
        int main(void)
        {
            int result;
            int number=15;//最大阶乘15
            for(int i=1;i<=number;i++)
            {
                result=dg(i);
                printf("%2d!=%d\n",i,result);
            }

        }

        int dg(int number)
        {
            if(number == 1 || number==0)//0与1的阶乘都是1
                return 1;
            else
                return dg(number-1)*number;//递归到number的值为1位止   

        }
    递归的次数不宜过多,太多会使栈溢出
    递归思想
        汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具
    一维数组和二维数组都做函数的形参
    变量作用域
        局部变量:
            1.在复合语句内定义的变量
            2.函数的形参
        全局变量
            1.函数之外定义
    变量只能在作用域内有效
    全局变量用于增加函数间数据联系
    全局变量与局部变量重名,局部变量有效---就近原则
        #include<stdio.h>
        int number=20;
        int main(void)
        {
            {
            int result;
            int number=15;
            printf("%d\n",number);//15
            }
            printf("%d",number);//20
        }
    变量存储方式
        1.静态存储--分配固定的存储空间
        2.动态存储--根据需要分配存储存储空间
    存储空间可分为
        1.程序区
        2.静态存储区
        3.动态存储区
    动态存储区中存放的
        1.函数形参
        2.函数中定义的没有使用static的变量
        3.调用函数时现场保护和返回地址
        对于这些数据,调用函数时动态分配存储空间,函数结束时释放这些空间。
        所以两次调用这个函数,分配的局部变量地址可能不一样
    函数和变量都有两个属性
        1.数据类型
        2.存储类别
    变量
        自动变量
            auto
            不写默认就是
            值释放
            动态存储
            每次都会给初值
        静态变量
            static
            值不释放
            静态存储
            只会给一次初值---静态变量在第一次调用才会执行
        寄存器变量
            register
            对于频繁使用的值,把值存储在寄存器中,提高程序效率
            但是对应现在的计算机,速度很快,所以这个操作不是很必要了
        全局变量
            函数外定义的变量
            作用域:从定义处到文件末尾
            静态存储
            使用extern可以扩展全局变量的"作用域"
                1.在文件中扩展
                2.扩展到其他文件
            使用statc可以把全局变量的作用域限制在本文件中
    作用域与生存期
        作用域---空间角度
        生存期---时间角度
    定义与声明
        需要建立存储空间的声明---    定义性声明---定义  int a;
        不需要建立存储空间的声明--    引用性声明---声明  extern a;
    内部函数与外部函数
        加static的函数--内部函数
            1.静态函数
            2.只能在本文件内使用
        加extern的函数--外部函数
            1.可以省略写extern
            2.默认是外部的
《结构体》
    用户建立用于存放不同数据类型的组合型的数据结构
    声明结构体的格式
        struct 结构体名 {成员列表};
        结构体类型名=truct+结构体名(结构体标记)
            #include<stdio.h>
            struct Student
            {
                int num;
                char name[20];
                char sex;
                int age;
                float score;
                char addr[30];
            };//声明结构体
            int main(void)
            {
                printf("%d",sizeof(struct Student));//68--获取结构在内存中占的字节数
                /*
                    计算机对内存的管理是以字为单位的,许多计算机系统以4个字节为一个字
                    类型             占空间     求余4剩余的空间
                    int num             4            0
                    char name[20]   20            0
                    char sex         1              3
                    int age            4            0
                    float score        4            0
                    char addr[30]    30            2
                                    
                    4+20+1+4+4+30=63    0+0+3+0+0+2=5
                    总:63+5=68个字节
                */
            }
    定义结构体类型变量
        1.先声明结构体类型,再定义该类型变量
            struct 结构体名{成员列表};//声明结构体
            struct 结构体名 结构体变量名;//定义结构体
        2.在声明类型的同时定义变量
            struct 结构体名{成员列表}结构体变量名列表;//声明类型的同时定义
        3.不指定结构体名而直接定义结构体类型的变量
            struct{成员列表}变量名列表;
            不能在去定义其他变量,用法不多
        说明:
            1.结构体类型名
            2.结构体名
            3.结构体变量名
            要分清他们
            4.结构体成员名可以与普通变量名重名,但是他们没有任何关系,属于不同的对象,互不干扰
    结构体的初始化与引用
        1.在定义结构体变量时对它的成员初始化
        2.C99允许只对某一成员初始化
        3.其他未初始化的成员
            数值型初始化 0
            字符型         '\0'
            指针类型     NULL
            其实他们的值都为0
        4.通过结构体变量名引用成员
            结构体变量名.成员名
        5.对结构体的成员只能每个的输入或输出
        6.结构体的成员中有结构体,通过成员运算符一级一级地找到最低的一级成员
        7.结构体变量的成员的变量可以像普通变量一样进行各种运算
        8.同类型的结构体变量可以相互赋值
        声明、定义、初始化
            #include<stdio.h>
            struct Student
            {
                int num;//学号
                char name[30];//姓名
                char sex;//性别
                int age;//年龄
                float score;//成绩
                char addr[30];//地址
            }student={1605406202,"蓝祥乐",'M',18,99.0,"广西"};//直接初始化
            int main(void)
            {
                /* 输出类型要抑制 */
                printf("学号=%d\n",student.num);  //学号=1605406202
                printf("姓名=%s\n",student.name); //姓名=蓝祥乐
                printf("性别=%c\n",student.sex);  //性别=M
                printf("成绩=%f\n",student.score);//成绩=99.000000
                printf("地址=%s\n",student.addr); //地址=广西
            }
        声明、定义、分别初始化
            #include<stdio.h>
            struct Student
            {
                int num;//学号
                char name[30];//姓名
                char sex;//性别
                int age;//年龄
                float score;//成绩
                char addr[30];//地址
            };
            int main(void)
            {
                struct Student student;//定义结构体变量
                /* 分别赋值 */
                student.num=1605406202;
                student.name[0]='l';
                student.name[1]='x';
                student.name[2]='l';
                student.name[3]='\0';//最好加'\0',字符串的结束标志   
                student.sex='男';//乱码 ASCII没有中文
                student.score=90.0;
                student.addr[0]='g';
                student.addr[1]='x';
                student.addr[2]='\0';
                printf("学号=%d\n",student.num);  //学号=1605406202
                printf("姓名=%s\n",student.name); //姓名=lxl
                printf("性别=%c\n",student.sex);  //性别=? //因为ASCII没有相应中文编码 --单个字符
                printf("成绩=%f\n",student.score);//成绩=99.000000
                printf("地址=%s\n",student.addr); //地址=gx
            }
        至简至美---能让用户喜欢
        声明、定义、使用扫描函数初始化
            #include<stdio.h>
            struct Student
            {
                int num;//学号
                char name[30];//姓名
                char sex[10];//性别 ---需要存中文请这样写
                int age;//年龄
                float score;//成绩
                char addr[30];//地址
            }student;//声明的同时定义
            int main(void)
            {
                /* 初始化 格式控制要与变量类型一致,不然会有意想不到的效果 */
                scanf("%d%s%s%d%f%s",
                                    &student.num,
                                    student.name,
                                    student.sex,
                                    &student.age,
                                    &student.score,
                                    student.addr);
                printf("学号=%d\n",student.num);  //学号=1605406202
                printf("姓名=%s\n",student.name); //姓名=lxl
                printf("性别=%s\n",student.sex);  //性别=男
                printf("成绩=%f\n",student.score);//成绩=99.000000
                printf("地址=%s\n",student.addr); //地址=广西
            }
《枚举》
        概念
            变量的值只有几种可能
            变量的值只限于列举出来的值的范围内
        声明枚举的一般形式
            enum [枚举名]{枚举元素列表};
        说明:
            1.C编译对枚举元素按常量处理--枚举常量
            2.C语言编译时默认认为他们的值为0,1,2,3,4,...
            3.可以在声明时指定枚举的值
            4.可以声明没有名字的枚举,直接定义枚举变量
            
        作用
            限制输入参数的值在枚举范围内,若果赋予其他值,就会出现错误信息,便于检测
            #include<stdio.h>
            enum Data
            {
                one,two,three,four
            };        
            int main(void)
            {
                /* 初值自动从零,自动加1 */
                printf("%d\n",one);//0
                printf("%d\n",two);//1
                printf("%d\n",three);//2
                printf("%d\n",four);//3
            }
            #include<stdio.h>
            enum Data
            {
                /* 初值从2开始,自动加1 */
                one=2,two,three,four
            };        
            int main(void)
            {
                printf("%d\n",one);//2
                printf("%d\n",two);//3
                printf("%d\n",three);//4
                printf("%d\n",four);//5
            }
            
            #include<stdio.h>
            enum Data
            {
                /* 初值从0开始,自己观察,自动加1 */
                one,two,three=10,four
            };        
            int main(void)
            {
                printf("%d\n",one);//0
                printf("%d\n",two);//1
                printf("%d\n",three);//10
                printf("%d\n",four);//11
            }
            #include<stdio.h>
            enum Data
            {
                one=2,two=1,three=10,four=3
            };                   //声明枚举
            int main(void)
            {
                enum Data date;//定义枚举变量
                date=one;       //把枚举成员赋给枚举变量
                printf("%d\n",date);//2
                printf("%d\n",two);//1
                printf("%d\n",three);//10
                printf("%d\n",four);//3
            }
            #include<stdio.h>
            enum
            {
                one,two=2,three=10,four
            };                   //声明无名枚举
            int main(void)
            {
                printf("%d\n",one);//0
                printf("%d\n",two);//2
                printf("%d\n",three);//10
                printf("%d\n",four);//11
            }
            #include<stdio.h>
            enum
            {
                one,two=2,three=10,four//在定义时可以赋值--第一次赋值
            };                   //声明无名枚举
            int main(void)
            {
                printf("%d\n",one=2);//报错 常量不能再被赋值
                printf("%d\n",two);//2
                printf("%d\n",three);//10
                printf("%d\n",four);//11
            }
            #include<stdio.h>
            enum hehe
            {
                one,two=2,three=10,four,five=10//在定义时可以赋值--第一次赋值
            };                   //声明枚举
            int main(void)
            {
               
                printf("%d\n",sizeof(enum hehe));// 枚举的大小是4个字节 所以枚举是以int常量来处理
                printf("%d\n",two);//2
                printf("%d\n",three);//10
                printf("%d\n",four);//11
            }
《typedef》
        概念
            指定新的类型名来替代已有的类型名
        应用
            1.简单的用一个新类型名替代原有的类型名
            2.命名一个简单的类型名替代复杂类型名
        定义新类型名的方法
            1.先按定义变量的方法写出定义体
            2.将变量名换成新类型名
            3.在最前面加typedef
            4.然后就可以使用新类型名去定义变量了
            习惯把新类型名的第一个字母用大写
            typedef只是对已存在的类型指定一个新的类型名字,而没有创造新的类型
            用typedef给数组类型、指针类型、结构体、共用体、枚举起别名,使编程更加方便
            typedef与#define的理解
                #define  ---预处理阶段、简单字符串替换
                typedef     ----编译阶段,不是字符串简单替换
            使用typedef声明的类类放在头文件中,便于移植
《共用体》
        概念
            几个变量共用同一段内存的结构
        格式
            union 共用体名{成员列表}变量表列;
        说明
            共用体所占内存长度等于最长的成员的长度
            共用体的变量地址和各成员的地址都是同一个值
            #include<stdio.h>
            union uu
            {
                int i;
                char c;
                float f;
                double b;
            };                 //声明共用体
            int main(void)
            {
                union uu uu; //定义共用体变量 共用体名与共用体变量名一样不影响
                printf("%d\n",sizeof(uu.i));// 4个字节
                printf("%d\n",sizeof(uu.c));// 1个字节
                printf("%d\n",sizeof(uu.f));// 4个字节
                printf("%d\n",sizeof(uu.b));// 8个字节
                printf("%d\n",sizeof(union uu));// 8个字节,共用体以最长类型的字节为准
            }
            union uu
            {
                int i;
                char c;
                float f;
                double b;
            };                 //声明共用体
            int main(void)
            {
                union uu uu; //定义共用体变量 共用体名与共用体变量名一样不影响
                uu.i=65;
                printf("%d\n",uu.i);// 65   
                printf("%c\n",uu.c);// 'A'   共用一个内存空间,数据都一样
                printf("%f\n",uu.f);// 0.000000  //解析失败
                printf("%f\n",uu.b);// 0.000000  //解析失败
            }
《结构体数组》
        格式
            struct 结构体名 {成员列表}数组名[数组长度];
        
    《结构体指针》
        概念
            指向结构体变量的指针
        1.指向结构体变量的指针
        访问成员的方法
            1.结构体变量.成员名
            2.*(指向结构体变量的指针).成员名
            3.指向结构体变量的指针->成员名----这个是第二中的简化
        运算符
            .  成员访问符
            -> 指向运算符
        2.指向结构体数组的指针
        不管指向结构体变量还是结构体数组,定义的指针类型要和指向类型要一致
    《用指针处理链表》
        链表
            是一种数据结构
        组成
            头指针
            结点
                1.用户需要的实际数据
                2.下一个结点的地址
            尾指针
            在内存中是不连续的--手拉手
        静态链表
        动态链表
《简单的指针》
指针是什么?
指针是存地址的变量,因此我们认为指针是一种地址类型。

地址是什么?
    是内存空间的字节编号,因此一个字节对应一个地址。

指针的意义?
    灵活访问一块空间。
   
指针的目的?
    找对象,搞对象

定义变量的格式?
    类型 变量名;
   
指针的三要素?
    指针变量名、指针变量类型、指针对象类型。
   
指针变量名、指针变量类型、指针对象类型如何分辨?
    定义        指针变量名        指针类型     指针对象类型
    int *p            p              int *             int
    为什么指针对象类型为int,因为*p代表的含义是指针的指向对象,等价于对象的变量名,因此类型为int.
   
变量名与类型?
    定义                        变量名            类型                    说明
    int a                        a                int                     基本类型
    int a[10]                       a                int [10]                数组类型
    int a(int a,int b)            a                int (int a,int b)        函数类型
    int *a                        a                int *                    指针类型
   
指针对象与指针对象类型?
    定义                        指针对象        指针对象类型                说明
    int *p                           *p               int                      本质是指针,指向一个整型型空间(整型指针)
    int (*p)[10]                   *p               int [10]                    本质是指针,指向一个数组空间(数组指针)
    int (*p)(int a,int b)              *p               int int(int a,int b)        本质是指针,指向一个函数空间(函数指针)
    int **p                           *p               int *                    本质是指针,指向一个指针空间(二级指针)
   
如果p=&a,就是p指向a空间,上下对比可知*p是a。
推理:p=&a ---> *p = *&a ---> *p = a
由上可知 *& = 1,*p表示就是指针对象的空间,所以抹去*p剩下就是指针对象的类型。

类型如何看?
    把变量名找出来,剩下的就是类型。
    int a; 变量名是a 类型int
    如果是指针,我们要找的一般是对象类型,把对象找出来,剩下的就是类型。
    int *p; 对象为*p 对象类型为int


以上文字的Word格式文档下载(内容和本网页上的一模一样,方便保存): 谭浩强C学习(上).docx (45.03 KB, 下载次数: 41)
回复

使用道具 举报

ID:262 发表于 2021-9-7 01:25 | 显示全部楼层
详细的笔记 规范的格式 赏心悦目啊
回复

使用道具 举报

ID:34149 发表于 2021-10-5 20:21 | 显示全部楼层
哇,这么认真,谢谢分享
回复

使用道具 举报

ID:970259 发表于 2021-10-7 15:15 | 显示全部楼层
不得了,不了的,不愧是高级工程师
回复

使用道具 举报

ID:908163 发表于 2021-10-16 19:44 | 显示全部楼层
看完了,总结的很好
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表