第8章 聚合数据类型

8-1 结构体【内存占用分析】

include/io_utils.h

#ifndef BASICC_IO_UTILS_IO_UTILS_H_
#define BASICC_IO_UTILS_IO_UTILS_H_

#include <stdio.h>
#include <limits.h>

void PrintBinary(unsigned int value);

#define PRINT_METADATA
#ifdef PRINT_METADATA
# define PRINTLNF(format, ...) printf("("__FILE__":%d) %s: "format"\n", __LINE__, __FUNCTION__ , ##__VA_ARGS__)
#else
# define PRINTLNF(format, ...) printf(format"\n", ##__VA_ARGS__)
#endif

#define PRINT_CHAR(char_value) PRINTLNF(#char_value": %c", char_value)
#define PRINT_WCHAR(char_value) PRINTLNF(#char_value": %lc", char_value)
#define PRINT_INT(int_value) PRINTLNF(#int_value": %d", int_value)
#define PRINT_LONG(long_value) PRINTLNF(#long_value": %ld", long_value)
#define PRINT_LLONG(long_value) PRINTLNF(#long_value": %lld", long_value)
#define PRINT_BINARY(int_value) PrintBinary((unsigned int) int_value);
#define PRINT_HEX(int_value) PRINTLNF(#int_value": %#x", int_value)
#define PRINT_BOOL(bool_value) PRINTLNF(#bool_value": %s", bool_value ? "true" : "false")
#define PRINT_DOUBLE(double_value) PRINTLNF(#double_value": %g", double_value)
#define PRINT_STRING(string_value) PRINTLNF(#string_value": %s", string_value)

#define PRINT_ARRAY(format, array, length) \
{ int array_index; \
for (array_index = 0; array_index < length; ++array_index) { \
  printf(format, array[array_index]); \
};\
printf("\n"); }

#define PRINT_INT_ARRAY_LN(array, length) \
{ int i; \
for (i = 0; i < length; ++i) { \
  PRINTLNF(#array"[%d]: %d", i, array[i]); \
}}

#define PRINT_INT_ARRAY(array, length) PRINT_ARRAY("%d, ", array, length)
#define PRINT_CHAR_ARRAY(array, length) PRINT_ARRAY("%c, ", array, length)
#define PRINT_DOUBLE_ARRAY(array, length) PRINT_ARRAY("%g, ", array, length)

#endif //BASICC_IO_UTILS_IO_UTILS_H_

01.struct.c

#include <stdio.h>
#include <io_utils.h>

int main() {
  /*
   * struct <结构体名> {
   *  <成员类型> <成员名>;
   *  ...
   * } <结构体变量>;
   */

  typedef struct Company {
    char *name;
    char *id;
    char *location;
  } Company;

  typedef struct Person {
    char *name;
    int age;
    char *id;
    Company *company;
    Company company2;
    struct {
      int extra;
      char *extra_str;
    } extra_value;
    struct Person *partner;
  } Person;

  struct Company company = {.name="imooc", .id="1212121"};
  struct Person person = {.name="bennyhuo", .id="12113322222", .company=&company,
      .company2={.name="imooc", .id="32323232"}
  };

  PRINT_INT(person.age);
  person.age = 30;

  //person.company->name
  //person.extra_value.extra

  PRINT_HEX(&person);

  Person *person_ptr = &person;

  puts(person_ptr->name);

  PRINT_INT(sizeof(Person));
  PRINT_INT(sizeof(person));

  struct {
    char *name;
    int age;
    char *id;
  } anonymous_person;

  Person person1 = {.name = "andy", .age = 20};
  PRINT_INT(person1.age);

  return 0;
}

8-2 结构体的内存对齐【内存占用优化】

02.memory_align.c

#include <io_utils.h>
#include <stddef.h>
//#pragma pack(2)
int main() {
  typedef struct Person {
    char *name;
    int age;
    char *id;
  } Person;

  struct Person person = {.name="bennyhuo", .id="12113322222"};

  PRINT_INT(person.age);
  person.age = 30;

  typedef struct {
    char a; // 1
    char b; // 1
//    __attribute((aligned(2))) int c; // 4 gcc only
//    _Alignas(8) int c; // 4 c11
    int c;
    short d; // 2
    double e; // 8
  } Align;

  typedef struct {
    char a; // 1
    char b; // 1
    short d; // 2
    int c; // 4
    double e; // 8
  } OptimizedAlign;


  Align align = {'a', 'b', 3, 4, 5.0};
  //PRINT_INT(_Alignof(align.c));
  PRINT_INT(offsetof(Align, e));
  return 0;
}

8-3 联合体【使用场景分析】

03.union.c

#include <io_utils.h>

#define OP_PRINT_INT 0
#define OP_PRINT_DOUBLE 1
#define OP_PRINT_STRING 2

typedef union Operand {
  int int_operand; // 4
  double double_operand; // 8
  char *string_operand; // 8
} Operand;

typedef struct Instruction {
  int operator;
  Operand operand;
} Instruction;

void Process(Instruction *instruction) {
  switch (instruction->operator) {
    case OP_PRINT_INT: PRINT_INT(instruction->operand.int_operand);
      break;
    case OP_PRINT_DOUBLE: PRINT_DOUBLE(instruction->operand.double_operand);
      break;
    case OP_PRINT_STRING: puts(instruction->operand.string_operand);
      break;
    default:
      fprintf(stderr, "Unsupported operator: %d\n", instruction->operator);
  }
}

int main() {
  PRINT_INT(sizeof(Operand));

  Operand operand; // = {.int_operand=5, .double_operand=2.0};
  operand.int_operand = 5;
  operand.double_operand = 2.0;
  PRINT_INT(operand.int_operand);
  PRINT_DOUBLE(operand.double_operand);

  Instruction instruction = {
      .operator = OP_PRINT_STRING,
      .operand = {
          .string_operand = "Hello World!"
      }
  };

  Process(&instruction);
  return 0;
}

8-4 枚举【多语言对比】

04.enum.c

#include <io_utils.h>

typedef enum FileFormat {
  PNG, JPEG = 10, BMP = 20, UNKNOWN
} FileFormat;

FileFormat GuessFormat(char *file_path) {
  FILE *file = fopen(file_path, "rb");
  FileFormat file_format = UNKNOWN;
  if (file) {
    char buffer[8] = {0};
    size_t bytes_count = fread(buffer, 1, 8, file);
    if (bytes_count == 8) {
      // bmp: 42 4D
      // png: 89 50 4E 47 0D 0A 1A 0A
      // jpeg: FF D8 FF E0
      if (*((short *) buffer) == 0x4D42) {
        file_format = BMP;
      } else if(*((long long *) buffer) == 0x0A1A0A0D474E5089) {
        file_format = PNG;
      } else if(*((int *) buffer) == 0xE0FFD8FF) {
        file_format = JPEG;
      }
    }
    fclose(file);
  }
  return file_format;
}

int main() {
  FileFormat file_format = PNG;
  FileFormat file_format_1 = 1;

  PRINT_INT(GuessFormat("images/c.png"));
  PRINT_INT(GuessFormat("images/c.jpeg"));
  PRINT_INT(GuessFormat("images/c.bmp"));
  PRINT_INT(GuessFormat("images/c.webp"));

  return 0;
}

8-5 案例:判断字节序

05.byte_order.c

#include <io_utils.h>

int IsBigEndian() {
  union {
    char c[2];
    short s;
  } value = {.s=0x100};

  return value.c[0] == 1;
}

int IsBigEndian2() {
  short s = 0x100;
  char *p = (char *)&s;
  return p[0] == 1;
}

int ToggleEndian(int original) {
  union {
    char c[4];
    int i;
  } value = {.i=original};

  char temp = value.c[0];
  value.c[0] = value.c[3];
  value.c[3] = temp;
  temp = value.c[1];
  value.c[1] = value.c[2];
  value.c[2] = temp;

  return value.i;
}

int ToggleEndian2(int original) {
  char *p = (char *)&original;
  char temp = p[0];
  p[0] = p[3];
  p[3] = temp;
  temp = p[1];
  p[1] = p[2];
  p[2] = temp;

  return original;
}

int main() {
  PRINT_INT(IsBigEndian());

  int original = 0x12345678;
  PRINT_HEX(ToggleEndian(original));
  return 0;
}

8-6 案例:单链表的基本实现

06.linked_list.c

#include <io_utils.h>
#include <stdlib.h>

typedef struct ListNode {
  int value;
  struct ListNode *next;
} ListNode;

ListNode *CreateNode(int value) {
  ListNode *node = malloc(sizeof(ListNode));
  if (!node) exit(1);

  node->value = value;
  node->next = NULL;
  return node;
}

void DestroyNode(ListNode **node_ptr) {
  (*node_ptr)->next = NULL;
  free(*node_ptr);
  *node_ptr = NULL;
}

ListNode *CreateList(int array[], int length) {
  if (length <= 0) return NULL;

  ListNode *head = CreateNode(array[0]);
  ListNode *current = head;
  for (int i = 1; i < length; ++i) {
    current->next = CreateNode(array[i]);
    current = current->next;
  }

  return head;
}

void DestroyList(ListNode **head) {
  if (!head || !(*head)) return;

  ListNode *current = *head;
  while (current) {
    ListNode *to_be_destroy = current;
    current = current->next;
    DestroyNode(&to_be_destroy);
  }

  *head = NULL;
}

void InsertNode(ListNode **head, int value, int index) {
  if (!head || index < 0) return;
  ListNode *new_node = CreateNode(value);
  if (index == 0) {
    new_node->next = *head;
    *head = new_node;
  } else {
    if (!(*head)) {
      *head = CreateNode(0);
    }
    ListNode *current = *head;
    while (index > 1) {
      if (!current->next) {
        current->next = CreateNode(0);
      }
      current = current->next;
      index--;
    }
    new_node->next = current->next;
    current->next = new_node;
  }
}

ListNode *FindNode(ListNode *head, int value) {
  while (head && head->value != value) {
    head = head->next;
  }
  return head;
}

void DeleteNode(ListNode **head, int value) {
  printf("Delete: %d\n", value);
  if (!head || !(*head)) return;
  if ((*head)->value == value) {
    ListNode *new_head = (*head)->next;
    DestroyNode(head);
    *head = new_head;
    return;
  }
  ListNode *current_node = *head;
  while (current_node->next && current_node->next->value != value) {
    current_node = current_node->next;
  }
  if (current_node->next) {
    ListNode *node_to_delete = current_node->next;
    current_node->next = current_node->next->next;
    DestroyNode(&node_to_delete);
  }
}

void PrintList(ListNode *head) {
  while (head) {
    printf("%d, ", head->value);
    head = head->next;
  }
  printf("\n");
}

int main() {
  int array[] = {0, 1, 2, 3, 4};
  ListNode *head = CreateList(array, 5);
  PrintList(head);
  InsertNode(&head, 100, 3);
  InsertNode(&head, 200, 0);
  InsertNode(&head, 300, 9);
  InsertNode(&head, 400, 10);
  PrintList(head);
  DestroyList(&head);
  PRINT_HEX(head);

  InsertNode(&head, 10, 0);
  PrintList(head);
  DestroyList(&head);
  InsertNode(&head, 10, 10);
  PrintList(head);
  DestroyList(&head);
  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)

get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
project(${ProjectId} C)

set(CMAKE_C_STANDARD 11)

include_directories("include")

file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
foreach(file ${files})
    get_filename_component(name ${file} NAME)
    add_executable(${name} ${file})
endforeach()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陶喜儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值