首页 > 系统相关 >枚举、typedef、位运算、堆内存-malloc 函数

枚举、typedef、位运算、堆内存-malloc 函数

时间:2024-08-10 23:23:19浏览次数:13  
标签:typedef int enum malloc 二进制 枚举 内存

目录

枚举定义

枚举值

枚举类型

枚举的优点

枚举的注意事项

示例程序

总结

typedef基本用法

复杂数据类型的重命名

位运算

位移操作

总结

堆内存

malloc 函数

free 函数

常见问题


枚举定义

在 C 语言中,枚举(enum)是一种数据类型,它允许定义一组具名的常量。使用枚举可以使代码更具可读性,避免使用魔法数字(magic numbers),并提供类型安全性。以下是有关 C 语言中枚举的一些基本知识点:

定义: 枚举通过 enum 关键字定义,定义的枚举类型包含一组具名的整数常量。

语法:

enum EnumName {
    Constant1,
    Constant2,
    ...
    ConstantN
};

示例:

#include <stdio.h>

// 定义一个枚举类型表示星期几
enum Weekday {
    SUNDAY,    // 默认从 0 开始
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY
};

int main() {
    enum Weekday today;
    today = WEDNESDAY; // 使用枚举常量

    if (today == WEDNESDAY) {
        printf("Today is Wednesday.\n");
    }

    return 0;
}

枚举值

  1. 默认值: 枚举常量的默认值从 0 开始,每个常量的值比前一个常量大 1。例如,在上面的示例中,SUNDAY 的值为 0,MONDAY 的值为 1,以此类推。

  2. 自定义值: 可以为枚举常量指定特定的整数值。如果没有显式指定值,后续常量的值将基于前一个常量的值自动递增。

    示例:

    enum ErrorCode {
        SUCCESS = 0,
        WARNING = 1,
        ERROR = 2,
        CRITICAL_ERROR = 10
    };
    

枚举类型

  1. 声明枚举类型变量: 通过定义的枚举类型声明变量,并用枚举常量给这些变量赋值。

    示例:

    enum Color {
        RED,
        GREEN,
        BLUE
    };
    
    enum Color favoriteColor;
    favoriteColor = GREEN;
    
  2. 枚举类型和整型: 枚举类型在内部表示为整数类型。可以将枚举值赋给整型变量,也可以将整型变量赋给枚举类型(注意可能会丧失类型安全性)。

    示例:

    enum Season {
        WINTER,
        SPRING,
        SUMMER,
        FALL
    };
    
    int seasonNumber = SUMMER; // 直接赋值,SUMMER 为 2
    enum Season currentSeason = (enum Season)4; // 强制转换,尽管 4 不在定义的范围内
    

枚举的优点

  1. 增强代码可读性: 使用具名常量代替魔法数字,使代码更具语义性和可读性。

  2. 避免硬编码: 避免在代码中直接使用数字,减少硬编码带来的错误。

  3. 类型安全: 提供类型安全性,防止将无关类型的值赋给枚举变量。

枚举的注意事项

  1. 存储大小: 枚举在不同的编译器和平台上可能有不同的存储大小,通常是 int 类型。标准 C 语言并未指定枚举的具体存储大小。

  2. 范围问题: 如果使用不在枚举定义范围内的值,可能会导致不可预知的行为。为确保代码的健壮性,尽量避免对枚举变量赋不合法的值。

  3. 不支持字符串: 枚举本身不支持将枚举值直接转换为字符串。要实现这种功能,需要手动编写代码来映射枚举值到对应的字符串。

示例程序

以下示例程序演示了如何使用枚举来表示方向,并实现一个简单的功能:

#include <stdio.h>

// 定义枚举类型
enum Direction {
    NORTH,
    EAST,
    SOUTH,
    WEST
};

// 函数:返回方向的字符串表示
const char* directionToString(enum Direction dir) {
    switch (dir) {
        case NORTH: return "North";
        case EAST: return "East";
        case SOUTH: return "South";
        case WEST: return "West";
        default: return "Unknown";
    }
}

int main() {
    enum Direction myDirection = EAST;

    // 打印方向
    printf("The direction is %s.\n", directionToString(myDirection));

    return 0;
}

总结

枚举是一种非常有用的工具,它可以使程序更具可读性和可维护性。通过合理使用枚举,能够提高代码的表达能力和减少错误。理解和掌握枚举的用法,有助于编写更清晰、更可靠的代码。

typedef基本用法

在 C 语言中,typedef 是一个用于定义新的数据类型名称的关键字。它允许开发者为已有的数据类型创建别名,从而使代码更具可读性和可维护性。以下是对 typedef 的详细介绍。

typedef 通过给已有的数据类型赋一个新的名字,来简化代码的书写和阅读。

语法:

typedef existing_type new_type_name;

示例:

#include <stdio.h>

typedef int Integer;  // 将 int 类型重命名为 Integer

int main() {
    Integer a = 10; // 使用新的类型别名
    printf("Value of a: %d\n", a);
    return 0;
}

复杂数据类型的重命名

typedef 特别适用于复杂数据类型,如结构体、联合体和指针等,使得代码更加简洁。

位运算

位运算是 C 语言中处理数据的低级操作,用于直接操作整数类型的二进制位。位运算常用于系统编程、性能优化以及硬件控制。以下是 C 语言中位运算的详细介绍:

运算符优先级从高到低:<<     >>     &    ^    |

位运算符

  1. 按位与(&

    按位与运算符 & 对两个操作数的每一位进行逻辑与操作。只有当两个操作数的对应位都是 1 时,结果位才是 1

    int a = 12;  // 二进制: 00001100
    int b = 7;   // 二进制: 00000111
    int result = a & b; // 二进制: 00000100,十进制: 4
    
  2. 按位或(|

    按位或运算符 | 对两个操作数的每一位进行逻辑或操作。只要两个操作数的对应位中有一个是 1,结果位就是 1

    int a = 12;  // 二进制: 00001100
    int b = 7;   // 二进制: 00000111
    int result = a | b; // 二进制: 00001111,十进制: 15
    
  3. 按位异或(^

    按位异或运算符 ^ 对两个操作数的每一位进行逻辑异或操作。当两个操作数的对应位不同,结果位为 1,相同则为 0

    int a = 12;  // 二进制: 00001100
    int b = 7;   // 二进制: 00000111
    int result = a ^ b; // 二进制: 00001011,十进制: 11
    
  4. 按位取反(~

    按位取反运算符 ~ 对操作数的每一位进行取反操作,即 0 变 11 变 0

    int a = 12;  // 二进制: 00001100
    int result = ~a; // 二进制: 11110011(在 8 位系统中),十进制: -13
    

    需要注意的是,按位取反会改变符号,因此在实际使用中要考虑计算机的补码表示方式。

  5. 左移(<<

    左移运算符 << 将操作数的二进制位向左移动指定的位数。左移相当于将数乘以 2 的移动位数次方。

    int a = 3;   // 二进制: 00000011
    int result = a << 4; // 二进制: 00110000,十进制: 48
    
  6. 右移(>>

    右移运算符 >> 将操作数的二进制位向右移动指定的位数。右移相当于将数除以 2 的移动位数次方。对于有符号整数,右移时符号位通常会扩展(即算术右移),对于无符号整数,右移则是逻辑右移。

    int a = 48;  // 二进制: 00110000
    int result = a >> 4; // 二进制: 00000011,十进制: 3
    

位移操作

  1. 位移操作 (<<):

    • << 是左位移操作符,它将一个数的二进制位向左移动指定的位数。
    • 每向左移动一位,相当于将数乘以 2
    • 位移操作不会改变数的符号位,只是改变了数的二进制表示。
  2. 2 << 6 的计算过程:

    • 2 的二进制表示是 00000010(假设使用 8 位二进制数)。
    • 当你将 2 向左移动 6 位时,结果会是 10000000
    • 10000000 的十进制值是 128

    计算过程如下:

    2 << 6 = 2 * (2^6) = 2 * 64 = 128
    

    因为每移动一位就是乘以 2,所以 2 向左移动 6 位等于 2 乘以 2 的 6 次方,即 128

总结

2 << 6 是将数字 2 向左移动 6 位,其结果是 128。这种操作是位操作中的一种常见方式,用于二进制处理和位掩码操作。

堆内存

定义: 堆内存是计算机内存的一部分,程序在运行时可以动态分配和释放。与栈内存不同,堆内存的生命周期由程序员控制,而不是由函数调用的自动管理。

malloc 函数

定义malloc(memory allocation)用于在堆上分配指定大小的内存块,并返回指向该内存块的指针。

函数原型:

void* malloc(size_t size);

参数:

  • size: 要分配的内存块的大小,以字节为单位。

返回值:

  • 成功时,返回一个指向分配内存的指针。
  • 失败时,返回 NULL

示例:

#include <stdio.h>
#include <stdlib.h> // 包含 malloc 和 free 的定义

int main() {
    // 动态分配内存
    int* ptr = (int*)malloc(sizeof(int) * 5); // 分配足够容纳 5 个 int 的内存

    if (ptr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }

    // 使用分配的内存
    for (int i = 0; i < 5; i++) {
        ptr[i] = i * 10;
    }

    // 打印分配的内存内容
    for (int i = 0; i < 5; i++) {
        printf("%d ", ptr[i]);
    }
    printf("\n");

    // 释放分配的内存
    free(ptr);

    return 0;
}

free 函数

定义free 用于释放之前使用 malloccalloc 或 realloc 分配的内存块,释放后的内存块可以被再次分配使用。

函数原型:

void free(void* ptr);

参数:

  • ptr: 指向要释放的内存块的指针。

返回值:

  • 无返回值。

注意事项:

  • 不要对同一块内存多次调用 free
  • 释放未分配的内存(如 NULL 指针)是安全的,但实际编程中最好避免。

示例:

#include <stdlib.h>

int main() {
    int* ptr = (int*)malloc(sizeof(int) * 10);
    
    if (ptr == NULL) {
        // 处理内存分配失败
        return 1;
    }
    
    // 使用分配的内存
    
    // 释放内存
    free(ptr);
    
    // ptr 现在是一个悬空指针(dangling pointer),不再使用它
    return 0;
}

常见问题

  1. 内存泄漏: 如果程序分配了内存但没有释放,这部分内存就无法再次使用,最终可能会导致程序内存不足。使用 malloc 时应确保所有分配的内存都用 free 释放。

  2. 悬空指针: 一旦释放了内存,指向该内存的指针会变成悬空指针。如果继续使用这些指针,可能会导致未定义的行为。释放内存后应将指针设置为 NULL

  3. 双重释放: 不应对同一块内存调用多次 free,这会导致程序崩溃或不稳定。每块内存应只被释放一次。

  4. 内存分配失败malloc 可能会失败,特别是在内存不足的情况下。始终检查 malloc 的返回值是否为 NULL,以处理内存分配失败的情况。

  5. 内存对齐: 某些平台可能要求内存对齐,因此分配内存时需要确保对齐需求得到满足。通常,malloc 处理这些细节,但在某些情况下,可能需要更精细的控制。

通过理解和正确使用 malloc 和 free,可以有效地管理程序的动态内存,避免内存泄漏和其他常见的内存管理问题。

标签:typedef,int,enum,malloc,二进制,枚举,内存
From: https://blog.csdn.net/2201_75286049/article/details/141091133

相关文章

  • springboot自定义枚举转换器
    在Spring框架中,枚举类型的转换可以通过自定义的转换器来实现,这样可以方便地在请求参数、表单数据、以及数据库查询中使用枚举类型。下面是关于Spring枚举转换器的详细介绍和使用方法:以排序枚举为例1.定义枚举类BaseEnum.javapackagecom.echo.model.enums;publicinterfa......
  • Linux内核解读(1)--内存管理与malloc原理
        本文主要关注Linux环境的堆内存的管理,详细解析Glibc与TCMalloc的malloc原理, 由于本人能力有限,难免会出现解读错误的地方,望各位大佬批评指正,后面也会在进一步解读中对本文进行修改。1、Linux内存分布        下图的布局形式是在内核2.6.7以后才引入的,......
  • Linux问题调试(4)--内存问题与tcmalloc
    1、问题概述      之前的文章介绍过Asan来定位内存泄漏问题,虽然已经被集成到各大编译器中,‌但它的使用可能受到特定环境或配置的限制。‌例如,‌在某些复杂的系统或应用程序中,‌ASan可能会因为与程序的交互复杂性而遇到挑战,‌导致难以准确诊断问题。‌Linux问题调试(2)--......
  • 阿斯蒂芬小技巧——枚举子集时间复杂度证明
    在写状压dp时,经常会见到如下句子:for(inti=0;i<(1<<n);i++){ for(intj=i;j!=0;j=(j-1)&i){ }}时间复杂度证明如下:单个\(x\)枚举子集复杂度易证(设\(y=log_2(x)\)):\[∑_{i=0}^{y}C^i_y\]使用二项式定理:\[(a+1)^n=∑_{i=0}^{n}C_n^i~a^i\]将上面的\(a\)......
  • Java enum(枚举)
    在Java中,enum(枚举)是一种特殊的数据类型,允许你定义一组命名的常量。这些常量通常代表一个固定的、有限的集合。例如,一年中的季节、交通信号灯的状态,或者一副扑克牌的花色。基本用法一个基本的enum定义如下:publicenumSeason{WINTER,SPRING,SUMMER,FALL}这里,Season......
  • new_d_array()函数接受一个int类型的参数和double类型的参数。该函数返回一个指针,指向
    /*下面是使用变参函数的一段程序:include<stdio.h>include<string.h>incude<stdarg.h>voidshow_array(constdoublear[],intn);double*new_d_array(intN,...);intmain(void){doublep1;doublep2;p1=new_d_array(5,1.2,2.3,3.4,4.5,5.6);p2=new_d_ar......
  • 枚举的使用场景
    枚举的使用场景目录枚举的使用场景基本定义带属性的枚举使用枚举枚举方法枚举与switch语句枚举迭代枚举与Java反射枚举实现接口枚举序列化基本定义publicenumDay{SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY;}带属性的枚举枚举可以拥有字段、......
  • `EnumSet` 和 `EnumMap` 枚举类
    EnumSet和EnumMap枚举类目录EnumSet和EnumMap枚举类EnumSet创建EnumSetEnumSet操作EnumMap创建EnumMapEnumMap操作EnumSetEnumSet是基于位向量(bitvector)的集合实现,专为枚举类型设计,提供了非常高效的内存和性能表现。EnumSet不允许包含null元素,并且所有元素都必......
  • 枚举
    枚举的定义在Java中,枚举(enum)是一种特殊的类,它可以用来定义一组常量。枚举类型是Java语言的关键字,用于定义枚举类型。枚举类型提供了一种方式,可以保证变量的值只能是预定义的常量集合中的一个。以下是枚举的一些基本特性和用法:定义枚举:枚举类型定义使用enum关键字publicenum......
  • 洛谷B3621枚举元组
    一道经典dfs题,很简单就是让你求1~k能组成多少个n位数。当然耐心足够的朋友可以尝试打表。dfs思路:1.定义数组a来存储每一次的组合,其中a[i]表示第i位的数字;3.递归一定要设定终止条件:如果枚举到了n+1位时,输出数组a并returnCode#include<bits/stdc++.h>usingnamespa......