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

news2025/1/19 17:01:48

学习所有语言的第一步几乎都是在控制台输出"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.coloradmin.cn/o/1880963.html

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

相关文章

如何为数据库中的位图添加动态水印

许多数据库存储了以blob或文件形式保存的位图&#xff0c;其中包括照片、文档扫描、医学图像等。当这些位图被各种数据库客户端和应用程序检索时&#xff0c;为了日后的识别和追踪&#xff0c;有时需要在检索时为它们添加唯一的水印。在某些情况下&#xff0c;人们甚至希望这些…

【数组】- 螺旋矩阵 II

1. 对应力扣题目连接 螺旋矩阵 II 题目简述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。如图&#xff1a; 2. 实现案例代码 public class SpiralMatrix {public static…

网页搜索如何优化效果最好?

可以使用长尾关键词策略&#xff0c;长尾关键词策略是指在SEO优化中&#xff0c;除了使用常规的短关键词外&#xff0c;还深入挖掘和使用那些更长、更具体的关键词。虽然这些关键词的搜索量较低&#xff0c;但竞争也较少&#xff0c;且更具针对性&#xff0c;因此往往能带来更高…

我的世界服务器-高版本服务器-MC服务器-生存服务器-RPG服务器-幻世星辰

生存为主&#xff0c;RPG乐趣为辅&#xff0c;重视每位玩家的建议&#xff0c;一起打造心目中的服务器&#xff0c;与小伙伴一起探险我的世界&#xff01; 服务器版本: 1.18.2 ~ 1.20.4 Q群&#xff1a; 338238381 服务器官网: 星辰毛毛雨-Minecraft高版本生存服务器我的世界…

PMBOK® 第六版 结束项目或阶段

目录 读后感—PMBOK第六版 目录 不论是阶段的收尾还是项目整体的收尾&#xff0c;都应是令人振奋的事。然而&#xff0c;在实际生活中&#xff0c;收尾工作却相当艰难。会遭遇负责人调离、换任&#xff0c;导致不再需要已购产品&#xff1b;项目收尾时对照招标文件或合同&…

[AIGC] 深入了解标准与异常重定向输出

在操作系统和编程环境下&#xff0c;有时我们需要更加精细地控制程序的输入或输出过程&#xff0c;这就涉及到了标准输入输出流&#xff0c;以及重定向的概念。接下来&#xff0c;我们将详细介绍标准输出、标准错误输出&#xff0c;以及如何进行输出重定向。 文章目录 1. 标准输…

企业im(即时通讯)作为安全专属的移动数字化平台的重要工具

企业IM即时通讯作为安全专属的移动数字化平台的重要工具&#xff0c;正在越来越多的企业中发挥着重要的作用。随着移动技术和数字化转型的发展&#xff0c;企业对于安全、高效的内部沟通和协作工具的需求也越来越迫切。本文将探讨企业IM即时通讯作为安全专属的移动数字化平台的…

坏越的小世界的一些修改调整

留言区感觉不够高大上&#xff0c;功能也比较简单。我想了想还是仿照小红书设计一个。 先写个静态 这边想了想是将留言和评论各放一个表和首次加载的放在一个表好。想了想还是选择了后者 不过在sql上这样可能会很麻烦&#xff0c;还是建议分表&#xff0c;看下布局 每次展开会…

QT加载安装外围依赖库的翻译文件后翻译失败的现象分析:依赖库以饿汉式的形式暴露单例接口导致该现象的产生

1、前提说明 VS2019 QtClassLibaryDll是动态库,QtWidgetsApplication4是应用程序。 首先明确:动态库以饿汉式的形式进行单例接口暴露; 然后,应用程序加载动态库的翻译文件并进行全局安装; // ...QTranslator* trans = new QTranslator();//qDebug() << trans->…

支付宝支付之收款码支付

文章目录 收款码支付接入流程安全设计系统交互流程交易状态统一收单交易支付接口请求参数测试结果查询支付撤销支付退款支付退款结果退款说明 收款码支付 继&#xff1a;支付宝支付之入门支付 接入流程 安全设计 支付宝为了保证交易安全采取了一系列安全手段以保证交易安全。…

路由器的ip地址与网关的区别是什么

在网络世界中&#xff0c;路由器扮演着至关重要的角色&#xff0c;它负责数据的传输和网络的互联。而在路由器的设置中&#xff0c;有两个常见的概念&#xff1a;IP地址和网关。那么&#xff0c;路由器的IP地址与网关的区别是什么&#xff1f;下面与虎观代理小二一起了解一下吧…

德国威步的技术演进之路(上):从软件保护到用户体验提升

德国威步自1989年成立以来一直专注于数字安全技术的研究和发展&#xff0c;在软件保护和数字授权领域树立了行业标杆&#xff0c;并在云端许可管理和物联网安全技术方面不断创新。德国威步的成就彰显了其对安全、创新和可持续发展的坚定追求。 德国威步将“完美保护、完美授权…

维卡币(OneCoin)是投资骗局!中国成维卡币传销重灾区,信徒们醒醒吧!创始人被通缉,生死不明!

维卡币(英文名&#xff1a;OneCoin)是一个隐藏在加密货币外表下的庞氏骗局&#xff0c;因传销诈骗和违法吸金被起诉&#xff0c;受害者遍布全球。它的创始人Ruja Ignatova因欺骗和洗钱被列为通缉嫌疑人&#xff0c;成为全球最大金融诈骗案件之一的逃犯&#xff0c;目前美国政府…

INS-GPS组合导航——卡尔曼滤波

系列文章目录 《SAR笔记-卫星轨道建模》 《SAR笔记-卫星轨迹&#xff08;三维建模&#xff09;》 《常用坐标系》 文章目录 前言 一、经典卡尔曼滤波 二、扩展卡尔曼滤波 三、无迹卡尔曼滤波 总结 前言 SAR成像仪器搭载于运动平台&#xff0c;平台的自定位误差将影响SAR…

Go 语言环境搭建

本篇文章为Go语言环境搭建及下载编译器后配置Git终端方法。 目录 安装GO语言SDK Window环境安装 下载 安装测试 安装编辑器 下载编译器 设置git终端方法 总结 安装GO语言SDK Window环境安装 网站 Go下载 - Go语言中文网 - Golang中文社区 还有 All releases - The…

单晶层状氧化物制作方法技术资料 纳离子技术

网盘 https://pan.baidu.com/s/1hjHsXvTXG74-0fDo5TtXWQ?pwd10jk 单晶型高熵普鲁士蓝正极材料及其制备方法与应用.pdf 厘米级铬氧化物单晶及其制备方法和存储器件.pdf 多孔氧化物单晶材料及其制备方法和应用.pdf 大单晶层状氧化物正极材料及其制备方法和应用.pdf 富钠P2相层状…

第四十篇——系统论:如何让整体效用大于部分之和?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 系统论&#xff0c;又从一个大的生态的角度去考虑&#xff0c;我们应该如…

足球虚拟越位线技术FIFA OT(一)

此系列文章用于记录和回顾开发越位线系统的过程&#xff0c;平时工作较忙&#xff0c;有空时更新。 越位线技术 越位技术已被用于图形化分析足球中潜在的越位情况。 自 2018 年将视频助理裁判 &#xff08;VAR&#xff09; 引入比赛规则以来&#xff0c;人们越来越关注准确确…

昇思MindSpore学习总结六——函数式自动微分

神经网络的训练主要使用反向传播算法&#xff0c;模型预测值&#xff08;logits&#xff09;与正确标签&#xff08;label&#xff09;送入损失函数&#xff08;loss function&#xff09;获得loss&#xff0c;然后进行反向传播计算&#xff0c;求得梯度&#xff08;gradients&…

【C语言】--分支和循环(1)

&#x1f37f;个人主页: 起名字真南 &#x1f9c7;个人专栏:【数据结构初阶】 【C语言】 目录 前言1 if 语句1.1 if1.2 else1.3 嵌套if1.4 悬空else 前言 C语言是结构化的程序设计语言&#xff0c;这里的结构指的是顺序结构、选择结构、循环结构。 我们可以用if、switch实现分支…