C语言学习

C语言学习大纲

  • 先写个框架,后面再根据项目情况进行拓展
  • 最近先把c/c++猛过一遍
  • 然后开始做几个项目,边做边写

1. C语言基础

  • C语言简介
    • C语言在嵌入式系统和Linux开发中的重要性
      嵌入式系统:
      C语言广泛用于嵌入式系统开发,因其能够直接操作硬件并高效管理资源。
      嵌入式设备如微控制器、传感器和通信模块通常采用C语言编写固件。
      Linux开发:
      Linux内核和许多系统工具、库都是用C语言编写的。
      C语言在Linux系统编程中被用于编写驱动程序、系统调用接口和高性能应用程序。
  • 开发环境

2. 基本语法

  • C程序的结构
    • 头文件和预处理指令:
      头文件包含库函数声明,如#include <stdio.h>。
      常见头文件及其解释:
1.<stdio.h>
作用:标准输入输出头文件。
包含内容:printf, scanf, fprintf, fscanf, getchar, putchar, fgets, fputs等函数的声明。

2.<stdlib.h>

作用:标准库头文件,包含了通用工具函数。
包含内容:malloc, free, calloc, realloc, atoi, atof, rand, srand, exit, qsort, bsearch等函数的声明。
预处理指令用于定义常量、宏和包含其他文件,如#define和#include。

3.<string.h>

作用:字符串处理头文件。
包含内容:strlen, strcpy, strncpy, strcat, strncat, strcmp, strncmp, strchr, strstr, memcpy, memset等函数的声明。

4.<math.h>

作用:数学函数头文件。
包含内容:sin, cos, tan, asin, acos, atan, exp, log, log10, sqrt, pow, ceil, floor, fabs等函数的声明。
  • main函数
    主函数是C程序的入口点,通常定义为int main()。
    main函数中包含程序的主要逻辑,返回值通常为0表示成功执行。
  • 注释
    单行注释使用//,多行注释使用/* … */。
  • 数据类型
    • 基本数据类型(int, char, float, double)
      • 基本定义和使用
 int:用于表示整数。
 int a = 10;
char:用于表示单个字符。
char c = 'A';
float:用于表示单精度浮点数。
float f = 3.14f;
double:用于表示双精度浮点数。
double d = 3.14159;   
  • 枚举类型(enum)

定义:
枚举类型(enum)用于定义一组命名的整型常量,提升代码可读性和维护性。

语法:

enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY };

使用:

enum Day today = MONDAY;

特点:
1.每个枚举常量的值默认从0开始,依次递增。
2.可以手动指定枚举常量的值。比如第一个默认为1,这样星期一到星期日的值就是1到7。

enum Day { SUNDAY =1, MONDAY, TUESDAY, WEDNESDAY , THURSDAY , FRIDAY, SATURDAY };
  • 类型修饰符(short, long, signed, unsigned)
    short:修饰整数类型,表示短整型,占用内存通常较小。
short int a;
short b; // 同样表示short int

long:修饰整数类型,表示长整型,占用内存通常较大。

long int c;
long d; // 同样表示long int

signed:表示有符号类型,可以存储正负整数。默认情况下,整数类型是有符号的。

signed int e;
signed f; // 同样表示signed in

unsigned:表示无符号类型,只能存储非负整数,范围是0到最大值。

unsigned int g;
unsigned h; // 同样表示unsigned int
  • 变量和常量
    • 变量的声明和初始化
      变量是存储数据的命名存储位置,可以在程序执行期间改变其值。在C语言中,声明变量的同时可以对其进行初始化。
      声明:
int age;

初始化:

int age = 25;
  • 常量的定义
    定义:
    常量(constant)是其值在程序运行期间不会改变的变量。
    常量的定义方式主要包括:
    1.#define预处理指令
    #define是C语言中的预处理指令,用于定义宏常量。它在编译时将所有出现该常量的地方替换为其值。
#define PI 3.14159
#define MAX_SIZE 100

特点:
宏常量没有类型检查。
宏常量不会占用内存空间。

2.const
const关键字用于定义具有类型的常量。const常量在程序运行期间不能被修改。

const double PI = 3.14159;

3.enum
使用枚举类型定义相关的整型常量,适用于表示一组相关值的常量。

  • 输入与输出

printf 函数:
用途:格式化输出数据到标准输出(如屏幕)。

printf("Integer: %d, Float: %f, Char: %c, String: %s\n", 10, 3.14, 'A', "Hello");

scanf 函数:
用途:从标准输入(如键盘)读取格式化输入数据。

scanf("%d %f %c %s", &num, &pi, &ch, str);

3. 操作符与表达式

  • 算术操作符
    用途:执行基本的数学运算。
    操作符:+(加),-(减),*(乘),/(除),%(取模)。

  • 关系操作符
    用途:比较两个值,返回真或假。
    操作符:==(等于),!=(不等于),>(大于),<(小于),>=(大于等于),<=(小于等于)。

  • 逻辑操作符
    用途:执行逻辑运算,返回真或假。
    操作符:&&(逻辑与),||(逻辑或),!(逻辑非)。

  • 位操作符
    用途:对整数类型的位进行操作。
    操作符:&(按位与),|(按位或),^(按位异或),~(按位取反),<<(左移),>>(右移)。

  • 赋值操作符
    用途:给变量赋值。
    操作符:=(赋值),+=(加并赋值),-=(减并赋值),*=(乘并赋值),/=(除并赋值),%=(取模并赋值)。

  • 其他操作符

    • 条件操作符(三目操作符)
      用途:简洁的条件判断。
      语法:condition ? expression1 : expression2
      示例:int max = (a > b) ? a : b;

    • sizeof操作符
      用途:返回数据类型或变量的大小(以字节为单位)。
      语法:sizeof(type or variable)
      示例:int size = sizeof(int);

    • 逗号操作符
      用途:顺序执行一系列表达式,返回最后一个表达式的值。
      语法:expression1, expression2, …, expressionN
      示例:int x = (a = 1, b = 2, a + b); // x为3

    • 类型转换操作符
      用途:强制转换变量的类型。
      语法:(type) expression
      示例:float f = (float) 10 / 3; // f为3.3333

4. 控制结构

  • 条件语句

    • if, if-else, else-if

    • switch-case
      用途:用于执行多分支选择操作,根据变量的值执行不同的代码块。

      switch (expression) {
          case constant1:
              // 代码块1
              break;
          case constant2:
              // 代码块2
              break;
          ...
          default:
              // 默认代码块
      }
      
  • 循环语句

    • for循环

    • while循环

    • do-while循环
      用途:用于执行至少一次的循环操作,然后根据条件决定是否继续执行。

        do {
          // 循环体代码
      } while (condition);
      
  • 跳转语句

    • break, continue
    • goto
    • return

5. 函数

  • 函数的定义与调用
    定义:指定函数的名称、返回类型和参数列表。

    int add(int a, int b) {
        return a + b;
    }
    

    调用:使用函数名称和参数调用函数。

    int result = add(2, 3);
    
  • 参数传递

    • 值传递
      将实际参数的值传递给函数的形参,函数内对参数的修改不会影响实际参数。

    • 指针传递
      将实际参数的地址传递给函数的形参,函数内对参数的修改会影响实际参数。

      void increment(int *a) {
          (*a)++;
      }
      
  • 递归函数
    定义:一个函数调用自身。

  • 作用域和生命周期

    • 局部变量和全局变量
      局部变量:在函数或代码块内定义,作用域仅限于函数或代码块内部,生命周期在函数调用期间。

        void func() {
          int localVar = 10;
      }
      

      全局变量:在所有函数外定义,作用域为整个程序,生命周期为程序的整个运行期

    • 静态变量
      1.局部静态变量
      定义:在函数内部使用static关键字定义的变量。
      作用域:局限于函数内部。
      生命周期:从程序开始到结束,值在函数调用之间保持不变。
      局部静态变量只能在定义它的函数内部使用,函数外部不能引用。

      void func() {
          static int count = 0;
          count++;
          printf("Count: %d\n", count);
      }
      
      

      2.全局静态变量
      定义:在所有函数外部使用static关键字定义的变量。
      作用域:局限于定义它的文件内部。
      生命周期:从程序开始到结束。

      static int globalVar = 0;
      
      void func1() {
          globalVar++;
          printf("globalVar: %d\n", globalVar);
      }
      
      void func2() {
          globalVar += 2;
          printf("globalVar: %d\n", globalVar);
      }
      

      全局静态变量可以在同一个源文件中的不同函数之间共享,但不能在其他源文件中访问。

6. 指针

对于指针学习有困惑的人,这里是我在网上找到的别人对于指针的理解:

假设你的朋友想知道你住在哪里。把你的家乡想象成内存,里面存储着很多房子(变量),还有定位它们的地址(指针)。你不会向朋友展示你家的照片,并期望他们能很快找到它。因此,你会给你的朋友你家的地址(一个指针),这样他们就能轻松找到它。

现在,让我们用适当的术语来表达:

C 想知道你引用的变量是什么。你有内存,里面存储着很多变量,还有定位它们的地址。你不能给 C 你的变量名,并期望 C 在所有其他变量中找到它,所以你将其地址引用为指针,这样 C 就能轻松找到它。

  • 指针基础
    定义:指针是存储变量地址的变量。
    声明:int ptr; 表示一个指向整数的指针。
    获取地址:使用&操作符,例如 ptr = &var;。
    解引用:使用
    操作符访问指针指向的值,例如 *ptr = 10;。

  • 指针与数组
    数组名:数组名本身就是一个指向第一个元素的指针。
    指针运算:可以通过指针遍历数组,例如 *(arr + i) 等价于 arr[i]。

  • 指针与字符串
    字符串:字符串在C中表示为字符数组,可以使用指针操作。
    字符串操作:例如 char *str = “Hello”;,可以通过指针访问每个字符。

  • 指针与函数
    函数指针:用于指向函数的指针。
    声明:int (*funcPtr)(int, int); 表示一个指向返回类型为int,参数为int, int的函数的指针。
    使用:例如 funcPtr = &functionName;,调用时 (*funcPtr)(arg1, arg2);。

  • 指针数组和函数指针
    指针数组:数组的每个元素都是一个指针,例如 int *arr[10]; 表示一个包含10个指针的数组。
    函数指针数组:数组的每个元素都是一个函数指针,例如 int (*funcArr[10])(int, int);。

ps:简单辨别

1.简单指针声明:int *ptr; 表示 ptr 是一个指向 int 类型的指针。
2.指针数组:int *arr[10]; 表示 arr 是一个包含10个指向 int 类型的指针的数组。
3.数组指针:int (*ptr)[10]; 表示 ptr 是一个指向包含10个 int 类型元素的数组的指针。

  • 动态内存分配
    • malloc, calloc, realloc, free

      • malloc
        用途:分配指定字节数的内存,未初始化。
        语法:void* malloc(size_t size);
        返回值:成功时返回指向已分配内存的指针,失败时返回NULL。

        	int *arr = (int *)malloc(10 * sizeof(int));
        	if (arr == NULL) {
        	    // 内存分配失败
        	}
        
      • calloc
        用途:分配指定数量和大小的内存块,并初始化为零。
        语法:void* calloc(size_t num, size_t size);
        返回值:成功时返回指向已分配内存的指针,失败时返回NULL.

        int *arr = (int *)calloc(10, sizeof(int));
        		if (arr == NULL) {
        		    // 内存分配失败
        		}
        
      • realloc
        用途:调整已分配内存块的大小,可以扩展或缩小内存块。
        语法:void* realloc(void *ptr, size_t size);
        返回值:成功时返回指向重新分配内存的指针,失败时返回NULL。

        int *arr = (int *)realloc(arr, 20 * sizeof(int));
        if (arr == NULL) {
            // 内存重新分配失败
        }
        
      • free
        用途:释放之前通过malloc、calloc或realloc分配的内存。
        语法:void free(void *ptr);

        free(arr);
        

      例子:

      #include <stdio.h>
      #include <stdlib.h>
      
      int main() {
          // 动态分配内存以存储10个整数
          int *arr = (int *)malloc(10 * sizeof(int));
          
          // 检查内存分配是否成功
          if (arr == NULL) {
              printf("Memory allocation failed\n");
              return 1; // 返回错误码
          }
      
          // 初始化数组
          for (int i = 0; i < 10; i++) {
              arr[i] = i + 1;
          }
      
          // 打印数组
          for (int i = 0; i < 10; i++) {
              printf("%d ", arr[i]);
          }
          printf("\n");
      
          // 释放内存
          free(arr);
      
          return 0;
      }
      
      

7. 数组和字符串

  • 一维数组
  • 多维数组
  • 字符数组与字符串
  • 字符串处理函数

8. 结构体与联合体

  • 结构体
  • 联合体
  • 枚举

9. 嵌入式系统编程

  • 嵌入式系统概述
    • 嵌入式系统的组成和特点
    • 嵌入式C语言编程的基础
  • 嵌入式开发工具
    • 嵌入式开发板(如ESP32, STM32)
    • 嵌入式开发环境设置
  • 硬件接口编程
    • GPIO编程
    • 定时器和中断
    • 串行通信(UART, SPI, I2C)
  • 嵌入式操作系统
    • FreeRTOS
    • 嵌入式Linux

10. Linux系统编程

  • Linux基础
    • Linux操作系统概述
    • 基本的Linux命令
  • Linux系统调用
    • 文件操作
      打开和关闭文件

      • fopen:用于打开文件,返回一个FILE*指针。
        语法:

        FILE* fopen(const char *filename, const char *mode);
        

        实例:

        FILE *fp = fopen("example.txt", "r");
        	if (fp == NULL) {
        	    printf("File could not be opened\n");
        	    return 1;
        	}
        
      • fclose:用于关闭文件
        语法:int fclose(FILE *fp);
        fclose(fp);

      读写文件
      1.fgets 和 fputs:用于从文件读取字符串和向文件写入字符串。

      语法:

      char* fgets(char *str, int n, FILE *fp);
      int fputs(const char *str, FILE *fp);
      

      示例:

      char buffer[100];
      if (fgets(buffer, 100, fp) != NULL) {
          printf("Read from file: %s", buffer);
      }
      fputs("Hello, World!\n", fp);
      

      2.fread 和 fwrite:用于从文件读取数据块和向文件写入数据块。
      语法:

      size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp);
      size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
      

      示例:

      int data[10];
      	fread(data, sizeof(int), 10, fp);
      	fwrite(data, sizeof(int), 10, fp);
      

      3.fprintf 和 fscanf:用于格式化输入输出。
      语法:

      int fprintf(FILE *fp, const char *format, ...);
      int fscanf(FILE *fp, const char *format, ...);
      

      示例:

      int x;
      		fprintf(fp, "Value: %d\n", x);
      		fscanf(fp, "%d", &x);
      
    • 进程管理

    • 内存管理

  • 多线程编程
    • pthread库
    • 线程同步(互斥锁、条件变量)
  • 网络编程
    • 套接字编程
    • TCP/IP协议

11. 实践项目

  • 嵌入式项目
    • 简单的传感器读取与显示
    • 温度监控系统
  • Linux项目
    • 基本的Shell工具开发
    • 简单的网络服务器

12. 调试与优化

  • 调试工具
    • GDB调试
    • 嵌入式调试器(JTAG, SWD)
  • 性能优化
    • 代码优化技巧
    • 内存优化
  • 多项目/多模块管理化
    • 使用头文件和源文件
      在C语言中,多模块管理通常通过将代码分割为多个头文件(.h)和源文件(.c)来实现。这种方法提高了代码的组织性和可维护性。

      • 头文件
        作用:声明函数、变量和数据类型。
        语法:

        // file1.h
        #ifndef FILE1_H
        #define FILE1_H
        
        void func1();
        void func2();
        
        #endif // FILE1_H
        
        
      • 源文件
        作用:定义函数和变量。

        // file1.c
        #include "file1.h"
        #include <stdio.h>
        
        void func1() {
            printf("Function 1\n");
        }
        
        void func2() {
            printf("Function 2\n");
        }
        
      • 使用 extern 关键字
        作用:声明在其他文件中定义的变量和函数。
        语法:

        extern int sharedVar;
        extern void sharedFunc();
        
    • 示例项目结构
      file1.h:

      #ifndef FILE1_H
      #define FILE1_H
      
      void func1();
      void func2();
      
      #endif // FILE1_H
      

      file1.c:

      #include "file1.h"
      #include <stdio.h>
      
      void func1() {
          printf("Function 1\n");
      }
      
      void func2() {
          printf("Function 2\n");
      }
      
      

      main.c:

      #include "file1.h"
      
      int main() {
          func1();
          func2();
          return 0;
      }
      
      
    • 编译和链接
      编译多文件项目时,需要将所有源文件一起编译并链接。例如,使用GCC编译器:

      gcc -o program main.c file1.c
      
  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值