在(二)中我们介绍了如何构建一个String结构体,本篇文章中,我们在继续编写几个函数,让String结构体能尽快的被使用起来。
有了构建,那么就应该有释放,因为我们的构建结构体中,使用了malloc函数,因此我们必须编写对应的释放函数,使其在堆上的内存能够被回收。
先介绍一下malloc函数:使用malloc函数需要引入stdlib.h
(c语言标准库头文件)。
malloc
函数(memory allocation),又称动态内存分配。用于申请一块连续的指定大小的内存块区域,以void*
类型返回分配的内存区域地址。当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到malloc
函数,且分配的大小就是程序要求的大小。
malloc
函数原型为:void *malloc(unsigned int size)
。其作用是在内存的动态空间中分配一个长度为size
的连续空间。此函数的返回值是分配区域的起始地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置。如果malloc
函数分配成功则返回指向被分配内存的指针(此空间中的初始值不确定),否则返回空指针NULL
。
当通过malloc函数分配的内存不在使用时,应使用free()函数将其释放。
我们编写释放String结构体的函数:
/**
* 释放String结构体所占用的堆空间
* 同时也会释放结构体内char* value指向的堆空间
*/
void free_string(String* str){
if(str != NULL){
if(str->value != NULL){
free(str->value);
str->value = NULL;
}
free(str);
str = NULL;
}
}
首先判断str结构式是否为NULL,当其不为NULL时,我们先释放String结构体中的value,因为其也是用malloc申请的,接着释放str,都是调用free函数,把对应的指针传递进去即可。
在释放完成后,我们显示的把str->value和str都设置为NULL,这是一个好习惯。这样做的好处是:
- 避免悬空指针错误:如果后续不小心再次使用该已被释放的指针,可能会导致程序崩溃或出现难以预料的错误。将其设置为
NULL
后,若不小心再次使用,程序更容易检测到这种错误,因为访问NULL
通常会引发明确的异常或错误提示。 - 提高代码可读性和可维护性:明确表明该指针已经不再指向有效内存,让其他开发者或后续维护代码的人能更清楚地理解其状态,减少因误解而产生的潜在问题。
有时需要快速的创建一个结构体,为了节省内存,我们只给结构体中的value一个空字符串(\0)即可。编写String* build_empty_string(void):
/**
* 创建一个空字符串的结构体
*/
String* build_empty_string(void){
char emp[1] = {'\0'}; // 创建一个空字符串
String* empstr = build_string(emp); // 构建空字符串的结构体
return empstr;
}
为了判断一个String结构体是否是一个空字符串,我们编写bool is_empty(String* str)函数:
/**
* 判断字符串是否为空串
* 字符串
* @param str 字符串结构体指针
* @return 字符串是否为空 true:空串 false:非空串
*/
bool is_empty(String* str){
if(str == NULL){
return true;
}
if(str->length == 0){
return true;
}
return false;
}
is_empty的逻辑是,如果str为NULL或者str的length结构体成员的值为0,都认为该String结构体为empty。
这里我们使用了bool,需要引入stdbool.h头文件,它包含了用于定义布尔类型 bool 的宏定义。布尔类型:bool 类型,用于表示真或假。其Linux下的源码:
/* Copyright (C) 1998-2021 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/*
* ISO C Standard: 7.16 Boolean type and values <stdbool.h>
*/
#ifndef _STDBOOL_H
#define _STDBOOL_H
#ifndef __cplusplus
#define bool _Bool
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
#define true ((_Bool)+1u)
#define false ((_Bool)+0u)
#else
#define true 1
#define false 0
#endif
#else /* __cplusplus */
/* Supporting _Bool in C++ is a GCC extension. */
#define _Bool bool
#endif /* __cplusplus */
/* Signal that all the definitions are present. */
#define __bool_true_false_are_defined 1
#endif /* stdbool.h */
后续,我将陆续介绍String结构体下的各函数的实现,以及如何使用String结构体。
敬请期待。