返回

C 生万物 | 指针进阶 · 炼狱篇

后端

指针的进阶用法:C 语言中指针炼狱之旅

指针在 C 语言中扮演着举足轻重的角色,它不仅是理解数据结构的关键,也是深入剖析内存管理的利器。对于 C 语言程序员而言,掌握指针的使用是必不可少的。本篇文章将带领各位踏上指针的进阶之旅,深入探讨指针的各种用法,帮助大家在 C 语言编程的道路上更上一层楼。

指针基础回顾

指针的本质是存储另一个变量地址的变量。指针变量可以指向不同的数据类型,包括基本数据类型和结构体。例如:

int* ptr; // 指向一个整数的指针
char* str; // 指向一个字符串的指针

通过指针变量,我们可以访问指向变量的值,这称之为指针解引用。以下代码演示了指针解引用:

int x = 10;
int* ptr = &x; // ptr 指向 x 的地址

// 使用指针变量解引用并访问 x 的值
printf("x = %d\n", *ptr); // 输出:x = 10

指针的进阶用法

指针运算

指针运算包括:

  • 指针加法和减法:可以访问指向变量的相邻元素。
  • 指针比较:比较两个指针变量是否指向同一个地址。
  • 指针递增和递减:改变指针变量的值,使其指向下一个或上一个元素。

指针数组

指针数组是指向一组指针的数组。指针数组可以用来存储指向不同变量或对象的指针。例如:

int* ptr[5]; // 一个指向 5 个整数指针的指针数组

// 将指针数组的每个元素指向一个整数变量
for (int i = 0; i < 5; i++) {
  ptr[i] = &i;
}

// 使用指针数组访问每个整数变量的值
for (int i = 0; i < 5; i++) {
  printf("%d\n", *ptr[i]); // 输出:0, 1, 2, 3, 4
}

指向函数的指针

指向函数的指针是指向函数地址的指针。指向函数的指针可以用来调用函数。例如:

void myFunction() {
  printf("Hello, world!\n");
}

// 定义一个指向 myFunction 函数的指针
void (*ptr)(void) = myFunction;

// 使用指针调用 myFunction 函数
ptr(); // 输出:Hello, world!

指向结构体的指针

指向结构体的指针是指向结构体变量地址的指针。指向结构体的指针可以用来访问结构体变量的成员。例如:

struct student {
  char name[20];
  int age;
};

struct student s = {"John Doe", 20};
struct student* ptr = &s;

// 使用指针访问结构体变量的成员
printf("%s\n", ptr->name); // 输出:John Doe
printf("%d\n", ptr->age); // 输出:20

指针在数据结构中的应用

指针在数据结构中有着广泛的应用,例如链表、栈和队列。

链表

链表是一种线性数据结构,由一系列称为节点的元素组成。每个节点包含一个数据项和一个指向下一个节点的指针。以下代码演示了链表的实现:

struct node {
  int data;
  struct node* next;
};

struct node* head = NULL; // 链表的头节点

// 在链表的末尾添加一个节点
void add_node(int data) {
  struct node* new_node = (struct node*)malloc(sizeof(struct node));
  new_node->data = data;
  new_node->next = NULL;

  if (head == NULL) {
    head = new_node;
  } else {
    struct node* temp = head;
    while (temp->next != NULL) {
      temp = temp->next;
    }
    temp->next = new_node;
  }
}

// 遍历链表并打印每个节点的数据
void print_list() {
  struct node* temp = head;
  while (temp != NULL) {
    printf("%d\n", temp->data);
    temp = temp->next;
  }
}

// 释放链表中的所有节点
void free_list() {
  struct node* temp;
  while (head != NULL) {
    temp = head;
    head = head->next;
    free(temp);
  }
}

int main() {
  // 在链表中添加一些节点
  add_node(1);
  add_node(2);
  add_node(3);
  add_node(4);
  add_node(5);

  // 遍历链表并打印每个节点的数据
  print_list();

  // 释放链表中的所有节点
  free_list();

  return 0;
}

栈是一种后进先出(LIFO)的数据结构。栈中的元素按照它们被添加的顺序进行存储,后添加的元素位于栈顶。以下代码演示了栈的实现:

struct stack {
  int* arr;
  int top;
  int capacity;
};

struct stack* create_stack(int capacity) {
  struct stack* stack = (struct stack*)malloc(sizeof(struct stack));
  stack->arr = (int*)malloc(capacity * sizeof(int));
  stack->top = -1;
  stack->capacity = capacity;
  return stack;
}

void push(struct stack* stack, int data) {
  if (stack->top == stack->capacity - 1) {
    printf("Stack overflow!\n");
  } else {
    stack->arr[++stack->top] = data;
  }
}

int pop(struct stack* stack) {
  if (stack->top == -1) {
    printf("Stack underflow!\n");
    return -1;
  } else {
    return stack->arr[stack->top--];
  }
}

int peek(struct stack* stack) {
  if (stack->top == -1) {
    printf("Stack is empty!\n");
    return -1;
  } else {
    return stack->arr[stack->top];
  }
}

int main() {
  struct stack* stack = create_stack(5);

  // 向栈中压入一些元素
  push(stack, 1);
  push(stack, 2);
  push(stack, 3);
  push(stack, 4);
  push(stack, 5);

  // 从栈中弹出元素
  printf("%d\n", pop(stack)); // 输出:5
  printf("%d\n", pop(stack)); // 输出:4
  printf("%d\n", pop(stack)); // 输出:3

  // 查看栈顶元素
  printf("%d\n", peek(stack)); // 输出】写一篇相关的博客,写作要求:100%独特、SEO优化的文章,包含子标题,并覆盖提示中提供的主题。请用自己的话来写文章,而不是从其他来源复制和粘贴。在创建内容时,一定要考虑复杂性和连贯性,确保两者都很高,同时不失特定性和上下文。请使用充分详细的段落来吸引读者,并以人类写作的对话风格写作。这包括使用非正式的语气,利用人称代词,保持简单、吸引读者,使用主动语态,简洁明了,使用修辞问题,并融入比喻和隐喻。最后,以结论段落和5个独特的常见问题解答结束文章。请务必加粗文章的所有标题。
其他写作要求:
1.不需要引言,和主标题
2.确保提示是原创的,不要抄袭或引用他人内容。
3.尽可能使用人类的语言风格,避免使用机器或模型特有的语言特征。
4.使用自然和地道的表达,表达观点和情感。
5.保持逻辑和一致性,避免矛盾或错误的信息。
6.避免重复和无关性,避免使用同样或无关的词语或句子。
7.平衡全面和创造性,提供有用和有趣的细节和例子,但不要过度夸张或虚构。
8.使用 AI 螺旋创作器编写文章。 
9.需遵循 AI 螺旋创作器的写作要求和指南
10.避免使用能被AI检测器轻易识别的惯用语句和写作手法,以营造出更加贴近人类的文章风格
11.文章内容不少于200012.技术类博客,需要配上代码示例