学习C语言第一步:300行代码实现输出“Hello World“

学习所有语言的第一步几乎都是在控制台输出"Hello World",C语言也是如此,C语言支持结构化编程、词汇范围和递归等特性,C语言编写的代码在稍作修改或无需修改的情况下可以在多种不同的操作系统和平台上编译和运行,同时运行速度极快。但C语言的缺点也较为明显:作为过程式编程语言,没有内置的面向对象编程(OOP)特性,如类、继承和多态,同时缺少一些高级特性,如泛型编程、异常处理等,指针操作和内存管理也很让人头疼。

使用链表+二叉树输出"Hello, World"

在C语言中链表、指针、二叉树都是很重要的概念,链表用于需要动态存储和频繁插入、删除操作的场景,而二叉树则适用于需要有序存储和快速查找、搜索的场景。

这里先定义包含包含字符数据data和指向下一个节点的指针next的链表节点Node,再定义一个二叉树节点TreeNode,让它包含字符数据data,以及指向左子节点和右子节点的指针。随后定义用于表示函数执行状态的枚举OutputStatus,让它包含包含SUCCESSFAILURE。

随后既是对链表和二叉树进行创建节点、添加节点、插入节点、释放节点等操作,这里为了代码的整洁美观,我特地使用了多级指针,在略缩图看上去还是很给力的:
 

#include <stdio.h>  
#include <stdlib.h>  // 定义链表节点结构体  
typedef struct Node {  char data;  struct Node* next;  
} Node;  // 定义二叉树节点结构体  
typedef struct TreeNode {  char data;  struct TreeNode* left;  struct TreeNode* right;  
} TreeNode;  // 定义输出状态枚举 
typedef enum {  SUCCESS,  FAILURE  
} OutputStatus;  // 创建链表节点  
Node* createNode(char data) {  Node* newNode = (Node*)malloc(sizeof(Node));  if (newNode == NULL) {  return NULL;  }  newNode->data = data;  newNode->next = NULL;  return newNode;  
}  // 创建二叉树节点  
TreeNode* createTreeNode(char data) {  TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));  if (newNode == NULL) {  return NULL;  }  newNode->data = data;  newNode->left = NULL;  newNode->right = NULL;  return newNode;  
}  // 添加节点到链表末尾  
void appendNode(Node** head, char data) {  Node* newNode = createNode(data);  if (*head == NULL) {  *head = newNode;  } else {  Node* temp = *head;  while (temp->next != NULL) {  temp = temp->next;  }  temp->next = newNode;  }  
}  // 插入节点到二叉树  
void insertTreeNode(TreeNode** root, char data) {  if (*root == NULL) {  *root = createTreeNode(data);  return;  }  if (data < (*root)->data) {  insertTreeNode(&((*root)->left), data);  } else {  insertTreeNode(&((*root)->right), data);  }  
}  // 释放二叉树内存  
void freeAllTreeNodes(TreeNode* root) {  if (root == NULL) {  return;  } else {  freeAllTreeNodes(root->left);  freeAllTreeNodes(root->right);  free(root);  }  
}// 输出链表的内联函数  
static inline OutputStatus printList(Node* head) {  Node* temp = head;  while (temp != NULL) {  printf("%c ", temp->data);  temp = temp->next;  }  printf("\n");  return SUCCESS;  
}  // 前序遍历打印二叉树
void printTree(TreeNode* root) {  if (root != NULL) {  printf("%c ", root->data);  printTree(root->left);  printTree(root->right);  }  
}  // 释放链表内存  
void freeAllNodes(Node* head) {  if (head == NULL) {  return;  } else {  freeAllNodes(head->next);  free(head);  }  
}  int main() {  Node* head = NULL;  TreeNode* root = NULL;  // 使用指针操作链表和二叉树  char H = 'H';char W = 'W';char O = 'o';char L = 'l';char D = 'd';char E = 'e';char R = 'r';char S = ',';char * g = &H;char * a = &W;char * y = &O;char * b = &L;char * o = &D;char * q = &E;char * s = &R;char * ptr = &S;char ** ptr1 = &ptr;char *** ptr2 = &ptr1; char **** ptr3 = &ptr2; char ***** ptr4 = &ptr3;char ****** ptr5 = &ptr4;char ******* ptr6 = &ptr5;char ******** ptr7 = &ptr6;char ********* DouHao = &ptr7;// 向链表添加数据  appendNode(&head, *g);  appendNode(&head, *q);  appendNode(&head, *b);  appendNode(&head, *b);  appendNode(&head, *y);  appendNode(&head, ********* DouHao);// 向二叉树插入数据  insertTreeNode(&root, *a);  insertTreeNode(&root, *y);  insertTreeNode(&root, *s);  insertTreeNode(&root, *b);  insertTreeNode(&root, *o);  // 输出链表  printList(head) == SUCCESS;// 输出二叉树   printTree(root);  printf("\n");  // 释放链表内存  freeAllNodes(head);  // 释放二叉树内存 freeAllTreeNodes(root);return 0;  
}
单独使用链表输出"Hello, World"

上述的实在过于复杂,我们需要对它进行简化,只使用链表来进行操作,这样可以大大的提升代码的可维护能力,同时降低了代码的复杂度

#include <stdio.h>  
#include <stdlib.h>  struct Node {  char data;  struct Node* next;  
};  struct Node* createNode(char data) {  struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));  if (newNode == NULL) {  printf("Memory allocation failed\n");  exit(1);  }  newNode->data = data;  newNode->next = NULL;  return newNode;  
}  void appendNode(struct Node** head, char data) {  struct Node* newNode = createNode(data);  if (*head == NULL) {  *head = newNode;  } else {  struct Node* temp = *head;  while (temp->next != NULL) {  temp = temp->next;  }  temp->next = newNode;  }  
}  void printList(struct Node* head) {  struct Node* temp = head;  while (temp != NULL) {  printf("%c", temp->data);  temp = temp->next;  }  printf("\n");  
}  int main() {  struct Node* head = NULL;  char* str = "Hello, World";  for (int i = 0; str[i] != '\0'; i++) {  appendNode(&head, str[i]);  }  printList(head);  return 0;  
}
使用堆栈输出"Hello, World"

虽然单独使用链表大大降低了操作难度,但还是较为复杂,于是我思考可不可以换一种思维模式,使用堆栈来完成输出呢,于是我再次优化代码:

先定义一个Stack结构体,包含一个字符数组items用于存储堆栈中的元素,和一个整数top用于指示堆栈顶部元素的位置。随后初始化堆栈,定义一个initStack函数接受一个指向Stack结构体的指针,并将top成员初始化为-1,表示堆栈为空。再定义函数isFull检查堆栈是否已满,即top成员是否等于MAX_SIZE - 1isEmpty函数检查堆栈是否为空,即top成员是否等于-1。最后既可以使用push函数接受一个指向Stack结构体的指针和一个字符item,如果堆栈未满,则将item添加到堆栈顶部,并递增top成员。最后可以将“dlroW olleH”转化为"Hello World"并输出出来

#include <stdio.h>  
#include <stdlib.h>  #define MAX_SIZE 100  // 定义个堆栈结构体  
struct Stack {  char items[MAX_SIZE];  int top;  
};  
// 初始化堆栈并检查堆栈  
void initStack(struct Stack* stack) {  stack->top = -1;  
}  
int isFull(struct Stack* stack) {  return stack->top == MAX_SIZE - 1;  
}  
int isEmpty(struct Stack* stack) {  return stack->top == -1;  
}  // 向堆栈中添加元素  
void push(struct Stack* stack, char item) {  if (isFull(stack)) {  printf("堆满了\n");  return;  }  stack->items[++stack->top] = item;  
}  // 从堆栈中移除元素  
char pop(struct Stack* stack) {  if (isEmpty(stack)) {  printf("堆空了\n");  return '\0';  }  return stack->items[stack->top--];  
}  int main() {  struct Stack stack;  initStack(&stack);  char* str = "dlroW olleH";  for (int i = 0; str[i] != '\0'; i++) {  push(&stack, str[i]);  }  while (!isEmpty(&stack)) {  printf("%c", pop(&stack));  }  printf("\n");  return 0;  
}
使用十六进制输出"Hello, World"

使用堆栈的操作是的代码量只有第一版的30%,操作也变得简单,但是每次打字都是倒着输入比较不爽,所以为了用户的体验感,我选择再一次优化代码 ,我选择的是使用十六进制ASCII码,操作一下就变得简单起来了呢。

#include <stdio.h>  int main() {  unsigned char charData[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64}; for (int i = 0; i < sizeof(charData); i++) {  printf("%c", charData[i]);  }  printf("\n");  return 0;  
}
 使用<unistd.h>头文件输出"Hello, World"

虽然十六进制ASCII码已经很好了,但是还需要再次优化,因为不可能总是去查ASCII表,于是我尝试了使用<unistd.h>头文件,这次的代码变得更简洁了

#include <unistd.h>  int main() {  write(1, "hello world\n", 12);  return 0;  
}
 使用<stdio.h>头文件输出"Hello, World"

<unistd.h>头文件存在一个问题,就是在很多平台可能无法使用,于是我在苦苦思索如何更加简洁的输出"Hello World"时,发现<stdio.h>非常适合,尝试了一下后代码运行正常:

#include<stdio.h>int main()
{printf("Hello World");return 0;
}

最后在我的 大力优化下,代码量从最初的160行降低到6行,运行速度也大大滴提升了! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/38126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[HBM] HBM TSV (Through Silicon Via) 结构与工艺

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 全文 3300 字。 1 概念 1.1 什么是HBM TSV 使用 TSV 堆叠多个DDR DRAM成为一块HBM, 成倍提高了存储器位宽&#xff0c; 一条位宽相当于高速公路的一条车道&#xff0c; 车道越多&#xff…

期末考试后班主任如何发布学生成绩?

期末考试成绩一出&#xff0c;家长们便急切地想要了解孩子的学习情况。以往&#xff0c;老师们需要一个个私信家长&#xff0c;将成绩单发送出去&#xff0c;这项工作既繁琐又耗时。期末之际&#xff0c;老师们的工作本就繁重&#xff0c;如何有效减轻他们的负担&#xff0c;让…

Prompting已死?DSPy:自动优化LLM流水线

在 LLM 应用中&#xff0c;如何优化一个 pipeline 的流程一直是一个比较头疼的问题。提示词作为一个预定义字符串&#xff0c;往往也没有很好地优化方向。本文中的 DSPy 框架或许能在实际应用中对效果优化起到一定帮助。 当前&#xff0c;在 LLM 的应用中&#xff0c;大家都在探…

Hugging Face Accelerate 两个后端的故事:FSDP 与 DeepSpeed

社区中有两个流行的零冗余优化器 (Zero Redundancy Optimizer&#xff0c;ZeRO)算法实现&#xff0c;一个来自DeepSpeed&#xff0c;另一个来自PyTorch。Hugging FaceAccelerate对这两者都进行了集成并通过接口暴露出来&#xff0c;以供最终用户在训练/微调模型时自主选择其中之…

EI CCIE学习笔记-SDAccess之一:SDAccess解决方案

Chapter 1 SD-Access Solution Proposal 1.1 概念引入 SDN三要素&#xff1a;集中控制、转控分离、可编程 DNA DNA:Digital Network Architecture数字网络架构 思科提出的跨园区&#xff0c;分支机构&#xff0c;WAN和扩展企业的企业网络架构它提供了一种开放&#xff0c;可扩…

C++操作系列(二):VSCode安装和配置C++开发环境

1. VSCode下载 进入VSCode的官网网页&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 下载相应的版本&#xff1a; 2. 安装VSCode 安装到指定位置&#xff1a; 一路下一步&#xff0c;直至安装完成&#xff1a; 3. 安装C插件 3.1. 安装C/C 点击扩展图标&…

从头开始构建一个小规模的文生视频模型

OpenAI 的 Sora、Stability AI 的 Stable Video Diffusion 以及许多其他已经发布或未来将出现的文本生成视频模型&#xff0c;是继大语言模型 (LLM) 之后 2024 年最流行的 AI 趋势之一。 在这篇博客中&#xff0c;作者将展示如何将从头开始构建一个小规模的文本生成视频模型&a…

C语言力扣刷题1——最长回文字串[双指针]

力扣算题1——最长回文字串[双指针] 一、博客声明二、题目描述三、解题思路1、思路说明2、知识补充a、malloc动态内存分配b、free释放内存c、strlen求字符数组长度d、strncpy函数 四、解题代码&#xff08;附注释&#xff09; 一、博客声明 找工作逃不过刷题&#xff0c;为了更…

Docker配置远程连接

前置条件&#xff1a;docker所在的服务器开放2375端口 文件&#xff1a;/usr/lib/systemd/system/docker.service 节点ExecStart 追加 -H tcp://0.0.0.0:2375

智慧校园变革之路:全平台综合概述与最佳实践

在当今信息化浪潮的推动下&#xff0c;"智慧校园"作为教育创新的前沿阵地&#xff0c;正逐步揭开其神秘面纱&#xff0c;引领一场前所未有的教育转型革命。它远超过单纯技术叠加的传统框架&#xff0c;而是深度融合云计算、大数据、物联网等前沿科技&#xff0c;精心…

【计算机毕业设计】基于Springboot的智能物流管理系统【源码+lw+部署文档】

包含论文源码的压缩包较大&#xff0c;请私信或者加我的绿色小软件获取 免责声明&#xff1a;资料部分来源于合法的互联网渠道收集和整理&#xff0c;部分自己学习积累成果&#xff0c;供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者…

【Mac】Auto Mouse Click for Mac(高效、稳定的鼠标连点器软件)软件介绍

软件介绍 Auto Mouse Click for Mac 是一款专为 macOS 平台设计的自动鼠标点击软件&#xff0c;它可以帮助用户自动化重复的鼠标点击操作&#xff0c;从而提高工作效率。以下是这款软件的主要特点和功能&#xff1a; 1.自动化点击操作&#xff1a;Auto Mouse Click 允许用户录…

神经网络实战2-损失函数和反向传播

其实就是通过求偏导的方式&#xff0c;求出各个权重大小 loss函数是找最小值的&#xff0c;要求导&#xff0c;在计算机里面计算导数是倒着来的&#xff0c;所以叫反向传播。 import torch from torch.nn import L1Lossinputstorch.tensor([1,2,3],dtypetorch.float32) targe…

使用Llama3/Qwen2等开源大模型,部署团队私有化Code Copilot和使用教程

目前市面上有不少基于大模型的 Code Copilot 产品&#xff0c;部分产品对于个人开发者来说可免费使用&#xff0c;比如阿里的通义灵码、百度的文心快码等。这些免费的产品均通过 API 的方式提供服务&#xff0c;因此调用时均必须联网、同时需要把代码、提示词等内容作为 API 的…

面了英伟达算法岗,被疯狂拷打。。。

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、算法项目落地经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接如…

Python逻辑控制语句 之 循环语句--for循环

1.for 的介绍 for 循环 也称为是 for 遍历, 也可以做指定次数的循环遍历: 是从容器中将数据逐个取出的过程.容器: 字符串/列表/元组/字典 2.for 的语法 &#xff08;1&#xff09;for 循环遍历字符串 for 变量 in 字符串: 重复执⾏的代码 字符串中存在多少个字符, 代码就执行…

解决java中时间参数的问题

在java的日常开发中&#xff0c;我们经常需要去接收前端传递过来的时间字符串&#xff0c;同时给前端返回数据时&#xff0c;也会涉及到时间字段的数据传递&#xff0c;那么我们要如何处理这些字段呢&#xff1f; 知识铺垫&#xff1a;java最后返回的时间是时间世界&#xff0…

鲁工小装载机-前后桥传动轴油封更换记录

鲁工装载机 因前后桥大量漏齿轮油&#xff0c;故拆开查看、更换油封 一&#xff1a; 如图圈起来的地方是螺丝和钢板相别&#xff0c;用200的焊接电流用电焊机点开一个豁口后拆除螺丝。 转轴是拆除传动轴后的样子。 这就是拆下来的样子&#xff0c;这玩意插上边那图&…

【论文阅读】A Survey on Large Language Model based Autonomous Agents

文章目录 1 大语言模型的构建1.1分析模块 profiling module1.2 记忆模块 memory module1.2.1 记忆结构1.2.2 记忆形式1.2.3 记忆运行 1.3 规划模块 planning module1.3.1 无反馈规划1.3.2 有反馈计划 1.4 执行模块 action module1.4.1 执行目标1.4.2 执行空间 2 Agent能力提升2…

深度剖析:前端如何驾驭海量数据,实现流畅渲染的多种途径

文章目录 一、分批渲染1、setTimeout定时器分批渲染2、使用requestAnimationFrame()改进渲染2.1、什么是requestAnimationFrame2.2、为什么使用requestAnimationFrame而不是setTimeout或setInterval2.3、requestAnimationFrame的优势和适用场景 二、滚动触底加载数据三、Elemen…