001_C语言的基本结构

[ 基本难度系数 ]:★★☆☆☆

一、C语言的基本结构

(1)、第一个程序:hello world

配置部署好 vsCode 之后,就可以直接在上面写代码了,新建一个新的C程序文件,向屏幕输出一串字符 “Hello World!”

下面,从整体上来分析一下这个最简单的C语言程序,将这个最简程序的各个部分剖析清楚,明白我们写下的每一个字符的具体含义。

(2)、第一个程序结构解析

1、头文件
#include <stdio.h>        // 告诉编译器在.h文件中(声明)有这么一个符号,你需要去其相应的.c文件里去找其源文件(实现(定义))
  1. C语言程序中,任何符号(包括变量和函数)的使用,都是需要提前声明的。
  2. 如果程序用到了系统库函数,那么就需要包含相应的系统头文件来进行声明。

上述代码中用到库函数printf,而这个函数的声明在头文件 stdio.h 中,因此在该程序中需要包含此头文件。

声明

  • 概念:对源文件外定义的某个符号进行描述的过程,称为声明
  • 作用:经过声明的符号,编译器才能正确识别和编译,否则编译器不认识,无法判定语法错误
  • 符号:变量、函数等
  • 示例:
// 声明一个变量符号number
extern int number = 100;     

// 声明一个函数符号function
extern void function(int size, char *buf);

// 注意:前面的extern的关键字是可以不加的
2、主函数
  1. 主函数是必须有的,每一个C语言程序都有main函数,哪怕是空的。
  2. 主函数的名字是固定的,叫 main ,这个函数名不可被挪作他用。
  3. 主函数是程序的入口,也就是程序开始运行的地方。
  4. 主函数分解如下:
// int:        返回值类型,代表主函数最终的执行结果是一个整型数据
// main:       main是函数名,这个名字不能变
// void:      是函数参数列表,可以省略,表示空的意思,就是没有参数的意思

int main(void)
{
   ........
}

在 Linux 环境下,主函数 main 根据程序最终是否需要接收外部命令行参数,实际上有两个版本:

// 不接收外部命令行参数的版本
int main(void)
{
    ...

}

// 接收外部命令行参数的版本
int main(int argc, char const *argv[])  
{
    ...
}
3、printf函数(标准输出 --- 屏幕设备)

C语言被称为是一种面向过程的模块化语言,所谓的模块,指得是一个个功能明确、各司其职的封装函数,它们就像一块块积木,被合理有机地拼搭起来,形成复杂、健壮的程序。

在这之中,系统标准C库提供了非常多“模块”,printf 就是其中之一,它的功能就是:向终端输出一段指定格式的数据。

面向对象:我吃饭,我唱歌,我洗澡,我走路,我打架

面向过程:吃饭,唱歌,洗澡,走路,打架

// 向终端输出一段字符串
printf("Hello World!\n");

解析:

a、常见的格式控制符:
一、基础格式控制:
    %d        // 十进制整数,decimalism
    %o        // 八进制整数,octonary
    %x          // 十六进制整数,hexadecimal
    %c        // 字符,character    
    %s        // 字符串,character string
    %f        // 单精度浮点数,float
    %p        // 输出地址、输出指针的值,pointer
 
二、格式控制拓展(后面讲):
    .........

示例代码:

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int    num      = 100;
    char   buf[128] = "shijienameda,woxiangdainiqukankan";
    float  f1       = 3.14;
    double f2       = 3.14;

    // 1、没有格式控制符的printf函数
    printf("hello world!\n");

    // 2、打印整型数
    printf("整型数:%d\n", num);        // 要求打印这个num的值的时候,用十进制数表示:decimalism
    
    // 3、打印八进制数
    printf("八进制数:%o\n", num);      // 要求打印这个num的值的时候,用八进制数表示:octonary

    // 4、打印十六进制数
    printf("十六进制数:%x\n", num);    // 要求打印这个num的值的时候,用十六进制数表示:hexadecimal
                
    // 5、打印字符
    printf("字符: %c\n", num);         // 要求打印这个num的值的时候,用字符表示:character
    /*
        一开始计算机中是没有固定的数据(1010...)代表字符的
        所以后面定了一个标准:ASCLL表(这个表描述了相关字符对应的数据(0-128))
    */

    // 6、打印字符串(因为num不是字符串格式的,所以不能打印或者说打印会有误)
    printf("字符串: %s\n", buf);        // 要求打印这个buf的值的时候,用字符串表示:character string
    /*  
        printf("字符串: %s\n", num); 
        类型不匹配
        format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
        格式百分号S要求参数类型为char *, 但是printf函数的参数2的类型却是int数据
    */

    // 7、打印小数(单精度浮点型)
    printf("小数(单精度): %f\n", f1);   // 要求打印这个f1的值的时候,用单精度浮点型来表示:float 

    // 8、打印小数(双精度浮点型)
    printf("小数(双精度): %f\n", f2);    // 要求打印这个f2的值的时候,用双精度浮点型来表示:double float 

    // 面试题3:
    /*
        判断两个浮点型数据是否一致
        if( f1 == f2)
        {
            printf("两个浮点型数相等\n");
        }
        else
        {
            printf("两个浮点型数不相等\n");
        }
    */
    // 9、打印地址数据(打印指针里面的数据(指针里面的数据就是地址数据))
    // printf("num的地址数据为: %p\n", num);       // 以地址的方式打印num的值(地址是用十六进制的方式打印的)(注意:地址是用十六进制打印的,但不意味着十六进制的数据是地址)
    printf("num的地址数据为: %p\n", &num);         // 打印num的地址

    return 0;
}
b、常见转义字符、显示特效转义字符:

转义字符通常前面有\符号

一、基本转义字符
    \n - 换行符。将光标移动到下一行的开始位置。******
    \t - 水平制表符。通常会将光标移动到下一个制表位。
    \\ - 反斜杠。用来表示实际的反斜杠字符。  
    \' - 单引号。用来表示实际的单引号字符。
    \" - 双引号。用来表示实际的双引号字符。
    \? - 问号。虽然问号本身不需要转义,但在某些情况下为了防止与三字母序列混淆,可能会用到。
    \a - 警报声。发出警报声。
    \b - 退格。将光标向后移动一个字符的位置。
    \f - 换页。跳转到下一页的开始位置。
    \r - 回车。将光标移动到当前行的开始位置,但不换行。
    \v - 垂直制表符。通常会将光标移动到下方的垂直制表位。
    \ooo - 其中ooo是1到3位的八进制数
    \xhh - 其中hh...是一个或多个十六进制数字。(\101 和 \x41 都代表大写字母 'A' 的ASCII码值65)
    

二、背景色、字体色显示转义字符
    a、格式:\033[40-47;30-37m
    b、说明:
        40/30:   黑色(背景色/字体色)
        41/31:   红色
        42/32:   绿色
        43/33:   黄色
        44/34:   蓝色
        45/35:   紫色
        46/36:   深绿色
        47/37:   白色
    c、使用:
        printf("\033[40;32m《学生信息管理系统》\n");

三、显示效果转义字符
    \033[0m           // 关闭特效
    \033[1m           // 高亮效果
    \033[4m           // 下划线效果
    \033[5m           // 闪烁效果(只有ubuntu18.04系统具备这个效果)
    \033[7m           // 反显(交换前景色和背景色)
    \033[8m           // 消隐(文本不可见)


四、光标设置
    \033[2J           // 清除屏幕
    \033[x;yH         // 定位光标(x:横轴坐标, y:纵轴坐标)
    \033[yA           // 上移光标(y是纵轴移动的位置)
    \033[yB           // 下移光标
    \033[xC           // 右移光标(x是横轴移动的位置)
    \033[xD           // 左移光标
    \033[H            // 复位光标
    \033[?25l         // 隐藏光标
    \033[?25h         // 显示光标
    \033[u            // 恢复光标位置
    \033[s            // 保存光标位置
    \033[K            // 清除从光标到行尾的内容

示例代码1

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    // 1、\n - 换行符:newline*********
    printf("hello word\n");

    // 2、\t - 水平制表符:Horizontal tab
    printf("111\t222\t333\t\n");
    
    // \\ - 反斜杠。
    printf("反斜杠:\\\n");

    // \' - 单引号。
    printf("单引号:\'\n");

    // \" - 双引号
    printf("双引号:\"\n");

    // \? - 问号
    printf("问号:\"\n");

    // %% - 想打印%,需要两个
    printf("百分号:%%\n");

    // \a - 警报声。发出警报声。:alert
    printf("警报声\a\n");   // 没有什么用

    // \b - 退格: backspace
    printf("nihaoi\b,shijie\n");   

    // \f - 换页。: form feed
    printf("nihao,weweoiweogweiogweiogweiohgweiohwioehgwe\f\n");  // 没有什么用

    // \r - 回车。:carriage return
    printf("qingge\r,nizhenshuai\n");   // 将光标移动到开头,重新覆盖
    for (int i = 0; i < 100; i++)
    {
        printf("\r\033[44;37m现在的进度为:%d%%\033[0m", i);
        usleep(50000);                 //  延时函数,延时微妙(1s == 100 0000us)
        fflush(stdout);                // 冲刷输出缓冲区(printf函数是将数据输出到输出缓冲区的,没有遇到截止或者是冲刷函数,是不会将字符串输出到屏幕中的)
    }

    //  \v - 垂直制表符。:vertical tad
    printf("\n111\v222\v333\v\n");
    
    // \ooo:八进制数
    printf("\144\n");   // 打印出d字符:d字符的ascll码值是100

    // \xhh:十六进制数
    printf("\x64\n");   // 打印出d字符:d字符的ascll码值是100
    return 0;
}

示例代码2

#include <stdio.h>
int main(int argc, char const *argv[])
{
    printf("\033[44;37m ========================== \033[0m\n");
    printf("\033[44;37m *                        * \033[0m\n");
    printf("\033[44;37m * 《 学生信息管理系统 》 * \033[0m\n");
    printf("\033[44;37m *                        * \033[0m\n");
    printf("\033[44;37m *   (1)、添加学生信息    * \033[0m\n");
    printf("\033[44;37m\033[1m\033[7m *   (2)、删除学生信息    * \033[0m\n");
    printf("\033[44;37m *   (3)、查看学生信息    * \033[0m\n");
    printf("\033[44;37m *   (4)、修改学生信息    * \033[0m\n");
    printf("\033[44;37m *   (5)、后台管理        * \033[0m\n");
    printf("\033[44;37m *                        * \033[0m\n");
    printf("\033[44;37m *                 退出(q)* \033[0m\n");
    printf("\033[44;37m ========================== \033[0m\n");
    return 0;
}
4、return语句

C语言中的关键字 return 的含义是结束一个函数,并返回某个数据(若有)。而具体到 main 函数中时,由于主函数 main 的结束同时也意味着整个程序的结束,因此在上述 Hello World 程序中 return 后整个程序就退出了。

int main(void)
{
    ... ...
    // 一般而言,函数正常退出返回0,非正常退出返回非0
    return 0;
}

一般而言,程序正常退出时,main函数返回值是0;当程序异常退出时,main函数返回值是非0。

注意:main函数的返回值是给上一级进程的,因此理论上讲在当前的单进程程序中,main函数的返回值究竟是多少都无所谓,因为根本没有去使用这个返回值,除非在多进程程序中,进程间才需要使用main函数的返回值来传递信息。

二、man帮助手册、在线文档的使用(第一手资料)

1、man手册(manual:手动的)

编程开发的过程中,需要使用众多的系统指令、各类函数库、系统调用、各类系统脚本文件等,这些种类繁多、功能各异的信息,可以通过统一的man手册来获取第一手资料(英文),man文档是帮助信息的权威通道,是大多数教程、书籍的知识来源。

由于 man 手册所需要罗列的帮助条目众多,因此 man 手册被妥善地分为9册,不同的帮助信息被放入对应的man分册中:

  • 在ubuntu命令行中敲
man man

  • man文档的九个分册:
    1. 可执行程序或Shell命令(默认已安装)
    2. 系统调用 (Linux内核自带的函数)
    3. 库函数 (外部的第三方函数)
    4. 特殊文件(通常出现在/dev目录下)
    5. 文件的特殊格式或协定(例如/etc/passwd的格式)
    6. 游戏
    7. 杂项(例如一些宏定义)
    8. 系统管理员命令(通常只能由管理员执行)
    9. 非标准内核例程
a、man手册的安装

在默认情况下,系统只安装第一册,其他的帮助信息一般需要用户自己手动安装,安装指令如下:

gec@ubuntu:~$ sudo apt install manpages
gec@ubuntu:~$ sudo apt install manpages-dev
b、man手册的查询

使用man手册查询命令、函数时,一般直接在man后面接上待查条目即可,但有时候会遇到同一个待查询的条目存在于多个man分册的情况,这就需要先罗列出该条目所在的分册信息,然后再根据需要去选择帮助文档的序号。

1、查询单一分册的条目:
gec@ubuntu:~$ man strcpy

2、查询存在于多个分册的条目:
# 先使用 -f 来查看有哪些分册包含了该条目
gec@ubuntu:~$ man -f printf
printf (1)           - format and print data
printf (3)           - print formatted output

# 根据需要,指定查询某一册帮助分册
gec@ubuntu:~$ man 3 printf
c、man手册的使用:
1、在Ubuntu系统终端上敲命令man -f strlen             // 查看该函数的man手册条目有几条,选择相应的页数
2、man 3 strcmp                                     // 阅读打开man手册文档
3、如何使用一个函数?
    a、函数的作用(NAME)
       strlen - calculate the length of a string    // 计算字符串的长度
    b、函数的头文件(SYNOPSIS)
        #include <string.h>
    c、函数原型(参数是什么、返回是什么)((DESCRIPTION))
        size_t strlen(const char *s);               //  size_t现在不用去理会,因为其本质就是int型数据(为了方便阅读)(被typedef改名的)(只不过可能会有一些限制条件,比如:unsigned)
        // 参数一:要计算长度的字符串

        注意:
            excluding the terminating null byte ('\0').不包括终止的空字节(“\0”)
            因为字符串其末尾默认自带一个'\0' (空字节)符号,比如:"nihao",其实有6个字符,其中一个是其末尾的'\0'符号
    d、函数的返回值(RETURN VALUE)
        返回字符串s的字节数(这个字符串s有多少个字符) 

示例代码:

#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    
    char buf[128] = "nihao";    // 创建128个字符空间大小的内存,将这个字符串内容给赋值进去
    size_t len = strlen(buf);    // 使用字符串函数strlen,去计算buf内存里面有几个字符(不包括'\0')
    printf("led = %lu\n", len);  // 由于size_t是long unsigned int数据类型,所以此处的格式控制符应为lud(d省略)
    return 0;
}

2、在线文档(C/C++)

https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5

三、代码风格规范

1、标识符命名(变量名、函数名):

    • 只能包含数字、字母以及下划线,不能包含其他任何特殊字符。
    • 只能以字母或者下划线开头。
    • 不能跟系统已有的关键字重名,也不能跟本命名空间(namespace)中具有相同作用域的其他标识符重名。
    • 尽量能一望便知,做到顾名思义,避免使用无意义字符

通常的命名方式(推荐):

a、函数名: 
    驼峰命名法:   FangHuiQing   
    下划线命名法: fang_hui_qing
    二合一法:     Fang_Hui_Qing或Fang_HuiQing
    
b、变量名:
    int led_num  = 0;    // 下划线命名法,小写
    int led_flag = 0;
    
c、宏定义:
    #define LED_ON       // 下划线命名法,大写

2、缩进:凡是有代码块的地方都必须缩进,一对大括号 { } 代表一个代码块

3、空格:标点符号后面,一般加空格

4、空行:不同逻辑段落中间,一般加空行

5、排版的快捷方式

让代码块整体左移: 选中代码块+shift键+tab键

让代码块整体右移: 选中代码块+tab键

注释/解除注释: 选中代码块+ctrl+/

练习

【1】、实验1:

使用 VSCode 编写一段代码,显示自己的学校和姓名

【2】、实验2:

麻花疼同学写了下面这个程序,请指出你认为不妥的地方。

#include "stdio.h"         
main{}
(
float g; h;
float tax, rate;
g = e21;
tax = rate * g;
printf("%f\n", tax);
)

【3】、实验3:

使用man手册查询strlen函数的用法,并编写一个程序试试它的效果。

【4】、实验4:练习一下基础的转义字符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值