C语言String结构体,模仿Java的String类(二)

本文延续上篇,介绍如何在C语言中定义和创建类似Java String的结构体,包括结构体成员、函数指针的定义以及如何通过`build_string`函数创建String对象。详细讨论了函数指针的使用以及结构体中函数的实现策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在C语言String结构体,模仿Java的String类(一)中,我为大家介绍了头文件的内容,在这里,我会介绍String结构体、以及如何创建String结构体、String结构体在头文件中函数是如何实现的。

首先我们来看看String结构体包含哪些成员:

从(一)中的结构定义来看,我们做了2件事情,首先使用结构体的不完整定义,先定义my_string这个结构体,然后通过typedef为my_string定义了一个类型别名String,方便在函数调用、函数声明中使用my_string的简单名,也就是:struct my_string可以用String替代。

struct my_string;   // 使用结构体的不完整定义
typedef struct my_string String;  // 定义字符串结构体的类型别名

接下来,就完整的定义my_string结构体,这样做的原因是我们需要在结构体的函数定义中使用String来作为参数。

我们在结构体中定义,保存字符串长度的length结构体成员,然后定义字符串内容的结构体成员char* value

int length;   // 字符串的长度, 不包含末尾的\0
char* value;  // 字符串的内容

接着,我们会模仿Java的String类代码,为my_string添加一些函数,这里用到了面向对象的设计。由于是c语言并没有Java语言类、this等特性,因此就用结构体来模仿了。主要思路是将一些函数指针定义为结构体的成员,函数指针如何定义呢?

可以这样看,假设需要一个获得字符串中某个索引的字符,那么可以定义一个函数:

char char_at(String* thisptr, int index);

根据c语言的语法规则,函数指针的定义,就应该是:

char (*char_at)(String* thisptr, int index);

对比一下,只是需要将普通的函数定义中,将函数名放到括号中,并在函数名的前面加一个星即可。如图:

参考上图,这就是函数指针的定义,它表示,这是一个名为char_at的函数指针,它可以指向一个函数,这个函数的返回值必须是char,需要有两个参数,一个是String结构体的指针,一个是int即可。

按照以上的介绍,我们就可以模仿Java的String中的相应方法,来定义我们的String结构体了。

具体的String结构体是如何定义的,请参见(一)的源代码,其中注释的很详细,就不在此占用篇幅过多介绍了。

如何创建String结构体,我设计了一个函数 String* build_string(const char* str),这个函数的目的是为了返回一个已创建好的String结构体指针。

创建结构体的代码以及结构体中函数的实现,我们都在my_string.c中完成,首先会引入必要的头文件。


/**
 *  引入C语言标准输入输出头文件stdio.h
 *  它包含了用于执行输入和输出操作的函数声明和宏定义,
 *  比如常见的printf()(用于输出)、scanf()(用于输入)等函数。
 *  通过在 C 程序中包含这个头文件,就可以使用这些与输入输出相关
 *  的函数来与标准输入输出设备(如屏幕、键盘等)进行交互。
*/
#include <stdio.h>

/**
 * 引入C语言标准库头文件stdlib.h
 * 它包含了用于执行内存管理、动态内存分配、随机数生成、环境变量和系统相关操作、数值转换函数等函数。
 * 内存管理:包含了如 malloc()、calloc()、realloc() 和 free() 等函数,用于管理内存。
 * 类型转换函数:包含了如 atoi()、atof()、atol() 等函数,用于将字符串转换为数值。
 * 
 */
#include <stdlib.h>
/**
 * 引入C语言标准字符串头文件string.h
 * 字符串处理:包含了如 strcpy()、strncpy()、strcat()、strncat()、strcmp()、
 * strncmp()、strchr()、strrchr() 等函数,用于处理字符串。
 * 字符串操作:包含了如 strlen()、strstr()、strtok() 等函数,用于操作字符串。
 */
#include <string.h>

/**
 * 引入C语言标准类型头文件ctype.h
 * 它包含了用于判断字符类型、大小写转换等函数。
 * 字符类型判断:包含了如 isalnum()、isalpha()、isdigit()、isspace() 等函数,用于判断字符类型。
 * 大小写转换:包含了如 tolower()、toupper() 等函数,用于转换字符大小写。
 */
#include <ctype.h>

/**
 * 引入C语言标准布尔类型头文件stdbool.h
 * 它包含了用于定义布尔类型 bool 的宏定义。
 * 布尔类型:bool 类型,用于表示真或假。
 */
#include <stdbool.h>

/**
 * 引入errno头文件
 * 它包含了用于获取系统错误信息的宏定义。
 */
#include <errno.h>

/**
 * 引入common_util.h头文件
 * 包含了一些自动以的工具函数声明和宏定义
 */
#include "common_util.h"

/**
 * 引入my_string.h头文件
 * 它包含了String结构体和相关函数声明
 */
#include "my_string.h"

接下来,我们编写String* build_string(const char* str)函数,该函数的主要作用是根据传入的char* str构建一个String结构体的指针,并返回给调用方。一个初步的实现如下:

/**
 * 创建一个String结构体
 * @param str 字符串
 * @return 新的String结构体指针
 *         结构体中的字符串指针指向字符串会trim到合适的大小
 */
String* build_string(const char* str){
    if(str == NULL){
        printf(">>> str参数的值为NULL!\n");
        return NULL;
    }
    String* new_str = (String*)malloc(sizeof(String));
    if(new_str == NULL){
        printf(">>> String结构体创建失败: %s\n", strerror(errno));
    }else{
        const char* tmppos = str; // 先保存str的地址
        if(*str == '\0'){
            new_str->value = (char*)malloc(sizeof(char) * 1);
            new_str->value[0] = '\0';
            new_str->length = 0;
            
        }else{
            // 先计算str的长度
            int i = 0;
            while(*str != '\0'){
                // printf(">>> str(%d): %c\n", i, *str);
                i++;
                str++;
            }
            new_str->length = i; //  保存字符的长度
            new_str->value = (char*)malloc(i+1); // 为value在堆里申请内存
            
            char* tmpval = new_str->value;
            // 复制字符串到value
            while(*tmppos != '\0'){
                *tmpval = *tmppos;
                tmppos++;
                tmpval++;
            }
            *tmpval = '\0'; // 字符串末尾加上'\0'
        }

        // 下边将绑定字符串结构体中定义的各种函数
        // 我们会实现一个函数就绑定一个,逐步完善。
        
    }
    return new_str;
}

首先,如果str是NULL那么,直接返回NULL,如果不是NULL, 我们就定义一个String结构体指针String* new_str, 并调用malloc方法为其在对上申请内存空间。

如果new_str为NULL,说明申请内存空间失败,那么调用strerro函数,输出错误原因。

如果new_str不为NULL,说明申请内存空间成功,那么先保存一下str,然后判断其是否是一个空字符串,也就是第一个字符是否是\0.

如果第一个字符是\0,那么我们就将new_str结构体的value在堆上分配一个字节的空间,将\0赋给value,将长度设置为0.

如果str的第一个字符不是\0,那么我们就先通过循环计算一下str的长度,然后调用malloc函数为new_str的value申请内存,接下来将str的每个字符赋值给value。

这样就完成了结构体的创建,我们返回new_str即可。

后续我们会逐步实现定义在String结构体中的函数,然后在String* build_string(const char* str)函数中将实现的函数绑定到String结构体中。

敬请期待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

会C、Java多种开发语言的金哥

您的鼓励是我创作的动力源泉!!

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

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

打赏作者

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

抵扣说明:

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

余额充值