嵌入式☞第二组(陆)

C语言:

指针

内存操作

我们对于内存的操作借助于 string.h 这个库提供的内存操作函数。

内存填充

  • 头文件: #include <string.h>
  • 函数原型: void *memset(void *s,int c,size_t n);
  • 函数功能:填充s开始的堆内存空间前n个字节,使得每个字节值为c。
  • 函数参数:
  • void *s:待操作内存首地址。
  • int c:填充的字节数据。
  • size_t n:填充的字节数。
  • 返回值:返回s
  • 注意:c常常设置为0,用于动态内存初始化
  • 案例:
/**
* 内存操作函数-memset
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
    // 在堆内存申请了一块存储空间
    int *p = (int*)malloc(4 * sizeof(int));
    if(!p)
    {
        puts("内存分配失败!");
        return;// 后续代码不需要执行
    }
    // 给这块内存进行初始化操作(填充)
    memset(p,0, 4 * sizeof(int));
    printf("%d\n",*(p+1));
    // 内存使用完毕,进行回收
    free(p);
    p = NULL;
}
int main()
{
    test1();
    return 0;
}    

内存拷贝

  • 头文件: #include <string.h>

  • 函数原型: void *memcpy(void *dest,const void *src,size_t n); 适合目标地址与源地址内存无

  • 重叠的情况。

  • void *memmove(void *dest,const void *src,size_t n);

  • 函数功能:拷贝src开始的堆内存空间前n个字节,到dest对应的内存中。

  • 函数参数:

  • void *dest:目标内存首地址。

  • void *src:源内存首地址。

  • ize_t n:拷贝的字节数。

  • 返回值:返回dest

  • 注意:内存申请了几个内存空间,就访问几个内存空间,否则数据不安全

  • 注意:memcpy与memmove一般情况下是一样的,更建议使用memmove进行内存拷贝;因为memmove函数是从自适应(从后往前或者从前往后)拷贝,当被拷贝的内存和目的地的内存有重叠时,数据不会出现拷贝错误。而memcpy函数是从前往后拷贝,当被拷贝的内存和目的地内存有重叠时,数据会出现拷贝错误。

案例:

/**
* 内存操作函数-memcpy|memmove
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
    // 申请内存
    // int *p1 = (int*)malloc(4 * sizeof(int));
    // int *p2 = (int*)malloc(6 * sizeof(int));
    // 给p1,p2填充数据,可以使用for循环..
    // for(int i = 0; i < 4; i++)
    // p1[i] = 10 + i;
    // memset(p2,0,6 * sizeof(int));
    // 创建数组
    int p1[4] = {11,12,13,14};
    int p2[6] = {21,22,23,24,25,26};
    // 将p1中的数据通过内存拷贝函数,拷贝到p2
    // memcpy(p2+2,p1+1,2*sizeof(int)) // int p2[6] = {21,22,12,13,25,26}
    memmove(p2+2,p1+1,2*sizeof(int));
    // 测试输出数组
    for(int i = 0; i < 4; i++)
        printf("%4d",p1[i]);
    printf("\n");
    for(int j = 0; j < 6; j++)
        printf("%4d",p2[j]);
    printf("\n");
    // 如果使用手动分配的指针,一定要记得释放内存
    // free(p1);
    // free(p2);
    // p1 = NULL;
    // p2 = NULL;
}
int main()
{
    test1();
    return 0;
}    

内存比较

  • 头文件: #include <string.h>

  • 函数原型: int memcmp(void *dest,const void *src,size_t n)

  • 函数功能:比较src和dest所代表的内存前n个字节的数据;

  • 函数参数:

  • void *dest:目标内存首地址

  • const void* src:源内存首地址

  • size_t n:比较的字节数

  • 返回值:

  • 0:数据相同

  • >0:dest中的数据大于src

  • <0:dest中的数据小于src

  • 注意:n一般和src,dest的总容量一样;如果不一样,内促比较的结果就不确定了。

  • 案例:

/**
* 内存操作-memcmp
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
    // 申请内存
    int *p1 = (int*)malloc(3*sizeof(int));
    int *p2 = (int*)malloc(4*sizeof(int));
    // int p1[4] = {1,0,3,6};
    // int p2[4] = {1,2,3,4};
    // int result = memcmp(p1,p2,4*sizeof(int));
    *p1 = 65;
    *p2 = 70;
    char *a = (char*)p1;// 类型转换
    char *b = (char*)p2;
    printf("%c,%c\n",*a,*b);
    int result = memcmp(a+1,b+1,1*sizeof(char));
    printf("%d\n",result);
}
int main()
{
    test1();
}

内存查找
头文件: #include <string.h>
函数原型: int *memchr|*memrchr(const void *s,int c,size_t n)
函数功能:在s开始的堆内存空间前n个字节中查找字节数据c
函数参数:
const void *s:待操作内存首地址;
int c:待查找的字节数据
size_t n:查找的字节数
返回值:返回查找到的字节数据地址
注意:如果内存中没有重复数据,memchr和memrchr结果是一样的;如果内存中有重复数据,memchr和memrchr结果就不一样:

举例:

void *memrchr(..);// 在使用时编译会报错,需要使用外部声明
// 外部申请
extern void *memrchr(..);
  • 举例:
/**
* 内存操作-memchr | memrchr
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 声明外部函数
extern void *memrchr(const void *s,int c,size_t n);
void test1()
{
    // 申请内存
    int *p = (int*)malloc(4*sizeof(int));
    if(!p)
    {
        puts("内存分配失败!");
        return;
    }
    // 给变量赋值
    for(int i = 0; i < 4; i++)
    {
        p[i] = i * 2;
    }
    p[3] = 4;
    // 输出
    for(int i = 0; i < 4; i++)
    {
        printf("%d,",p[i]);
    }
    printf("\n");
    // 内存查找 memchr
    int *x = (int*)memchr(p,4,4*sizeof(int));
    printf("%p--%p--%d\n",x,p,*x);
    // 内存查找 memrchr
    int *y = (int*)memrchr(p,4,4*sizeof(int));
    printf("%p--%p--%d\n",y,p,*y);
    // 回收内存
    free(p);
    p = NULL;
}
int main()
{
    test1();
}    

构造类型

数据类型分类

  1. 基本类型
    整数型
    短整型:short(2个字节
    整型(默认):int(4个字节
    长整型:long(8个字节
    长长整型:long long
    浮点型
    单精度:float(4个字节
    双精度:double(8个字节
    字符型:char(1个字节
  2. 指针类型
    数据类型*: int*,char*,float*等
    void*:任意数据类型的指针
  3. 空类型
    void:没有返回值或没有形参(不能定义变量
  4. 自定义类型/构造类型
    结构体类型:struct
  • 共用体类型(联合体):union
  • 枚举类型:enum

注意:整数型和字符型分有符号signed和无符号unsigned,默认是有符号,有符号可以省略关键字signed

结构体

结构体的定义

  • 定义:自定义数据类型的一种,关键字 struct ,结构体类型的变量可以存储多个不同数据类型的数据。
  • 定义格式:
struct 结构体名
{
数据类型1 成员名称1;
数据类型2 成员名称2;
...
}

注意:结构体中定义的变量,我们称之为成员变量。

  • 格式说明:

  • 结构体名:合法的标识符,建议单词的首字母大写

  • 数据类型n:C语言支持的所有类型

  • 成员名称:合法的标识符,就是变量的命名标准

  • 数据类型n 成员名称n:类似于定义变量,定义了结构体中的成员

  • 注意:

  • 结构体在定义的时候,成员不能赋值

  • 举例:

struct Cat
{
    int age = 5;// 错误,结构体定义的时候,成员不能赋值
    double height; // 正确
}
  • 常见的定义格式:
  • 方式1:常规定义(命名结构体,只定义类型)—推荐
struct Student
{
    int num;// 学号
    char name[20];// 姓名
    char sex;// 性别
    int age;// 年龄
    char address[100];// 家庭住址
}
  • 方式2:定义匿名结构体(常用于作为其他结构体的成员使用)
struct Dog
{
    char *name;// 姓名
    int age;// 年龄
    struct // 此时这个结构体就是匿名
    {
        int year;// 年
        int month;// 月
        int day;// 日
    } birthday;
}

注意:定义匿名结构体的同时必须定义结构体变量,否则编译报错,结构体可以作为另一个结构体的成员。

总结:

  1. 结构体可以定义在局部位置,也可以定义在全局位置;
  2. 全局位置的结构体名和局部位置的结构体名可以相同,就近原则(和普通变量的定义同理)
  • 结构体类型的使用:

利用结构体类型定义变量,定义数组;结构体类型的使用与基本数据类型的使用类似。

结构体变量的定义

  • 三种形式定义结构体变量:

    结构体变量也称为结构体的实力。

  • 第一种

① 先定义结构体
② 然后使用 struct 结构体名 变量名 ;

// 先定义结构体(先定义结构体这个数据类型)
struct A
{
int a;
char b;
}
// 定义结构体变量
struct A x;
struct A y;
  • 第二种

    在定义结构体的同时,定义结构体变量;

    // 定义结构体的同时定义结构变量
    struct A
    {
    int a;
    char b;
    } x,y;
    struct A z;
    

    此时定义了一个结构体A,x和y是这个结构体类型的变量。

    • 第三种:不推荐

    在定义匿名结构体的同时,定义结构体变量;

    struct
    {
    int a;
    char b;
    } x,y;
    struct
    {
    int a;
    char b;
    } z;
    

    此时定义了一个没有名字的结构体(称为匿名结构体);y,x是这个匿名结构体类型的变量;

    • 匿名结构体:—弊大于利(尽量少用)

    • 优点:少写一个结构体名称

    • 缺点:只能使用一次;定义的结构体类型的同时就必须定义变量

    • 应用场景:

    • 当结构体的类型只需要使用一次,并且定义类型的同时定义变量。

    • 作为其他结构体的成员使用。

    • 定义结构体的同时,定义结构体变量初始化

    struct Cat
    {
    int age;
    char color[20];
    } cat;
    
    • 结构体成员部分初始化是,大括号不能省略。

    • 结构体的成员,没有默认值,是不确定的数

    • 案例:

      /**
      * 结构体变量的定义
      */
      #include <stdio.h>
      // 先定义结构体,再定义结构体变量
      void fun1()
      {
          // 先定义结构体
          struct A
          {
              int a;
              char b;
          };
          // 再定义结构体变量
          struct A x;
          struct A y;
      }
      // 定义结构体的同时定义结构体变量
      void fun2()
      {
          struct A
          {
              int a;
              char b;
          } x,y;
          struct A z;
      }
      // 定义匿名结构体的同时定义结构体变量
      void fun3()
      {
          struct
          {
              int a;
              char b;
          } x,y;
          struct
          {
              int a;
              char b;
          } z;
      }
      int main()
      {
          fun1();
          fun2();
          fun3();
          return 0;
      }    
      

      结构体变量的使用

      • 结构体变量访问结构体成员
      • 格式
      结构体变量名.成员名;
      

      可以通过访问给成员赋值(存数据)
      可以通过访问获取成员的值(取数据)

      • 结构体变量未初始化,结构体的成员值随机(不确定)

      • 结构体变量在定义时,可以初始化

      • 建议用大括号标明数据的范围

      • 结构体成员初始化时,可以部分初始化,部分初始化时一定要带大括号标明数据的范围

      • 案例

      /**
      * 结构体变量的初始化
      */
      #include <stdio.h>
      /* 全局的结构体(数据类型) */
      struct Dog
      {
          char *name;// 姓名
          int age;// 年龄
          char sex;// M:公,W:母
      };
      /* 先定义,再初始化 */
      void fun1()
      {
          // 定义一个结构体
          // struct Dog
          // {
          // char *name;// 姓名
          // int age;// 年龄
          // char sex;// M:公,W:母
          // };
          // 定义结构体变量
          struct Dog dog;
          // 给结构体变量的成员赋值
          dog.name = "小黑";
          dog.age = 5;
          // 访问结构体变量的成员
          printf("%s,%d,%c\n",dog.name,dog.age,dog.sex);
      }
      /* 定义的同时初始化 */
      void fun2()
      {
          // 定义结构体变量并初始化
          struct Dog dog = {"小黑",23,'M'};
          // 修改成员的值
          dog.name = "小白";
          // 访问结构体变量的成员
          printf("%s,%d,%c\n",dog.name,dog.age,dog.sex);
      }
      int main()
      {
          fun1();
          fun2();
          return 0;
      }    
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值