博客
关于我
音视频系列--c语言学习(结构体,指针,位运算,内存管理,异常指针)
阅读量:263 次
发布时间:2019-03-01

本文共 4806 字,大约阅读时间需要 16 分钟。

C语言入门:结构体、指针与内存管理

C语言作为一门底层编程语言,在音视频开发中具有重要地位。掌握其基本语法和数据结构是每个开发者的必修课。本文将从结构体、指针、位运算、内存管理等方面入手,为读者提供实用的编程知识。


一、结构体

1.1 结构体类型的定义

结构体是一种用户自定义的数据类型,用于存储多个不同数据类型的数据。其定义方式如下:

struct Person { 
char name[64];
int age;
};
typedef struct {
char name[64];
int age;
} Person;

注意事项:在定义结构体时,不能直接给成员赋值。结构体只是一个类型定义,变量分配空间时才会赋值。


1.2 结构体变量的定义

结构体变量可以通过以下方式定义:

struct Person { 
char name[64];
int age;
} p1; // 定义类型同时定义变量
struct {
char name[64];
int age;
} p2; // 定义类型同时定义变量
struct Person p3; // 通过类型直接定义

1.3 结构体变量的初始化

结构体变量可以通过以下方式初始化:

struct Person { 
char name[64];
int age;
} p1 = { "john", 10 };
struct {
char name[64];
int age;
} p2 = { "Obama", 30 };
struct Person p3 = { "Edward", 33 };

1.4 结构体成员的使用

通过指针或数组方式访问结构体成员:

#include 
#include
#include
struct Person {
char name[64];
int age;
};
void test() {
// 栈上分配空间
struct Person p1;
strcpy(p1.name, "John");
p1.age = 30;
// 堆上分配空间
struct Person* p2 = (struct Person*)malloc(sizeof(struct Person));
strcpy(p2->name, "Obama");
p2->age = 33;
printf("Name:%s Age:%d\n", p1.name, p1.age);
printf("Name:%s Age:%d\n", p2->name, p2->age);
}

1.5 结构体赋值

结构体变量可以相互赋值,但不会影响原变量的空间:

struct Person { 
char name[64];
int age;
};
void test() {
// 在栈上分配空间
struct Person p1 = { "John", 30 };
struct Person p2 = { "Obama", 33 };
printf("Name:%s Age:%d\n", p1.name, p1.age);
printf("Name:%s Age:%d\n", p2.name, p2.age);
// 将p2的值赋值给p1
p1 = p2;
printf("Name:%s Age:%d\n", p1.name, p1.age);
printf("Name:%s Age:%d\n", p2.name, p2.age);
}

二、指针强化

2.1 指针变量

指针是一种数据类型,用于存储内存地址。以下是指针的基本使用示例:

void test01() {
int* p1 = 0x1234; // 1
int*** p2 = 0x1111; // 2
printf("p1 size:%d\n", sizeof(p1)); // 8字节
printf("p2 size:%d\n", sizeof(p2)); // 8字节
int a = 10;
p1 = &a;
printf("p1 address:%p\n", p1); // 0x7fffe080
printf("p1 address:%p\n", p1); // p1值的地址
printf("a address:%p\n", &a); // a元素的地址
}

2.2 空指针

空指针(NULL指针)用于表示不指向任何对象。可以通过以下方式赋值:

void test() {
char *p = NULL; // 空指针
// 读写空指针会导致错误
strcpy(p, "1111"); // err
char *q = 0x1122; // 野指针
strcpy(q, "2222"); // err
}

2.3 野指针

野指针是指指针未初始化或指向已释放的内存。避免野指针的出现:

  • 初始化指针为 NULL。
  • 释放后的指针立即置空。

  • 2.4 间接访问操作符

    通过 * 操作符解引用指针:

    void test01() {
    int a = 10;
    int* p = &a;
    *p = 20;
    int b = *p; // 必须确保内存可写
    const char* str = "hello world!";
    *str = 'm';
    printf("a:%d\n", a);
    printf("*p:%d\n", *p);
    printf("b:%d\n", b);
    }

    2.5 指针的步长

    指针的步长由其指向的数据类型决定:

    int a = 0xaabbccdd;
    unsigned int *p1 = &a; // p1指向整数类型,步长为4字节
    unsigned char *p2 = &a; // p2指向字符类型,步长为1字节
    printf("%x\n", *p1); // aabbccdd
    printf("%x\n", *p2); // dd
    printf("p1 =%d\n", p1); // 6421980
    printf("p1+1=%d\n", p1 + 1); // 6421984
    printf("p2 =%d\n", p2); // 6421980
    printf("p2+1=%d\n", p2 + 1); // 6421981

    三、位运算

    3.1 位逻辑运算符

    C语言提供丰富的位运算符:

    3.1.1 按位取反 ~

    ~(10011010) 01100101
    unsigned char a = 2; // 00000010
    unsigned char b = ~a; // 11111101

    3.1.2 位与 &

    (10010011) & (00111101) = (00010001)
    val &= 0377; // 将val的前三个字节置为0

    3.1.3 位或 |

    (10010011) | (00111101) = (10111111)
    val |= 0377; // 将val的前三个字节置为1

    3.1.4 位异或 ^

    (10010011) ^ (00111101) = (10101110)
    val ^= 0377; // 将val的前三个字节两两异或

    3.1.5 常用用法

    • 打开位flag | 00000100
    • 关闭位flag & ~flag
    • 转置位flag ^ 0xff
    • 交换两个数
    int a = 10;
    int b = 30;
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;

    四、指针详解

    4.1 指针的作用

    指针用于存储内存地址,常用于数组、链表和动态内存分配。

    4.2 指针的定义

    指针的定义可以是单级或多级:

    int *p; // int*类型的指针
    int *p[3]; // int**类型的指针,指向数组
    int (*p)[3]; // 指针指向数组
    int **p; // 两级指针

    4.3 指针的算术运算

    指针加减操作会移动内存地址:

    char a[20] = "You_are_a_girl";
    int *ptr = (int *)a;
    printf("* ptr addr %p\n", ptr); // 0x1000f000
    ptr += 1;
    printf("* ptr addr %p\n", ptr); // 0x1000f004
    printf("* ptr=%c\n", *ptr); // 'r'

    五、内存分配

    C语言提供 malloccallocreallocfree 函数用于内存管理。

    5.1 使用方式

    • malloc(size): 分配 size 字节内存。
    • calloc(n, size): 分配 n 个 size 字节的内存,初始化为 0。
    • realloc(ptr, size): 修改已有指针的内存大小。
    • free(ptr): 释放 ptr 所指向的内存。

    六、内存管理机制

    6.1 内存区域

  • 代码区:存放程序代码和常数。
  • 静态区:存放全局变量和静态变量。
  • 栈区:存放函数参数和局部变量。
  • 堆区:存放动态分配的内存。
  • 6.2 内存分配与释放

    使用 mallocfree 函数时,需谨慎管理内存:

    #include 
    #include
    #include
    void print_array(char *p, int n) {
    for (int i = 0; i < n; i++) {
    printf("p[%d] = %d\n", i, p[i]);
    }
    }
    int main(int argc, char *argv[]) {
    char *p = (char *)malloc(1024 * 1024 * 1024); // 分配内存
    memset(p, 'a', sizeof(int) * 10); // 初始化内存
    int i = 0;
    for (i = 0; i < 10; i++) {
    p[i] = i + 65; // 'A' 到 'J'
    }
    print_array(p, 10); // 打印数组
    free(p); // 释放内存
    return 0;
    }

    七、异常指针

    7.1 悬空指针

    悬空指针指向已释放的对象,需及时置空。

    int *p; // 未初始化,属于悬空指针

    7.2 野指针

    野指针指向垃圾内存,需避免使用。

    void test() {
    int *p; // 野指针
    *p = 10; // 错误
    }

    7.3 空指针

    空指针通过 NULL 表示不指向任何对象。

    int *p = NULL; // 空指针

    通过以上内容,希望读者能够掌握 C语言中的结构体、指针和内存管理的基础知识,为后续的音视频开发打下坚实的基础。

    转载地址:http://eihx.baihongyu.com/

    你可能感兴趣的文章
    Mysql order by与limit混用陷阱
    查看>>
    mysql order by多个字段排序
    查看>>
    MySQL Order By实现原理分析和Filesort优化
    查看>>
    mysql problems
    查看>>
    mysql replace first,MySQL中处理各种重复的一些方法
    查看>>
    MySQL replace函数替换字符串语句的用法(mysql字符串替换)
    查看>>
    mysql replace用法
    查看>>
    Mysql Row_Format 参数讲解
    查看>>
    mysql select, from ,join ,on ,where groupby,having ,order by limit的执行顺序和书写顺序
    查看>>
    MySQL Server 5.5安装记录
    查看>>
    mysql server has gone away
    查看>>
    mysql skip-grant-tables_MySQL root用户忘记密码怎么办?修改密码方法:skip-grant-tables
    查看>>
    mysql slave 停了_slave 停止。求解决方法
    查看>>
    MySQL SQL 优化指南:主键、ORDER BY、GROUP BY 和 UPDATE 优化详解
    查看>>
    MYSQL sql语句针对数据记录时间范围查询的效率对比
    查看>>
    mysql sum 没返回,如果没有找到任何值,我如何在MySQL中获得SUM函数以返回'0'?
    查看>>
    mysql sysbench测试安装及命令
    查看>>
    mysql Timestamp时间隔了8小时
    查看>>
    Mysql tinyint(1)与tinyint(4)的区别
    查看>>
    MySQL Troubleshoting:Waiting on query cache mutex
    查看>>