关于串算法中使用free(str->ch);无法执行后继代码的情况

异常

在写串算法时,有这么一段代码,添加之后下面的代码就无法正确执行了:

    if (str->ch) {
        free(str->ch);
        str->ch=NULL;
    }

错误代码

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char *ch;
    int length;
} String;

int assign(String *str, char *ch) {
    // 0.参数校验,如果 str 中已有字符,那么释放原串空间,因为我们会给它重新分配空间
    if (str->ch) {
        free(str->ch);
        str->ch=NULL;
    }

    // 1.统计常量字符串 ch 中的字符个数,只有知道它的字符个数,我们才能清楚为 str 分配多少个字符空间
    // 局部变量,存储常量字符串 ch 中的字符个数
    int len = 0;
    // 注意,我们不能直接操作 ch,因为是一个指针变量,在下面的操作后我们会移动指针,会修改掉 ch 原本的值,后面如果需要再使用就不是传入的参数值,所以要创建一个临时局部变量引用它的值来进行操作
    char *c = ch;
    // 从头到尾扫描常量字符串,以结束标记 '\0' 作为循环结束条件
    while (*c != '\0') {
        // 计数器加一
        len++;
        // 指针加一,继续下一个字符
        c++;
    }

    // 2.为串 str 分配空间并赋值
    // 2.1 如果常量字符串长度为 0,那么串 str 也该为一个空串
    if (len == 0) {
        str->ch = NULL;
        str->length = 0;
        return 1;
    }
        // 2.2 如果常量字符串长度不为 0,那么将常量字符串中所有字符赋给串 str
    else {
        // 给串分配 len+1 个存储空间,多分配一个空间是为了存放 '\0' 字符
        str->ch = (char *) malloc(sizeof(char) * (len + 1));
        // 判断是否分配空间成功
        if (str->ch == NULL) {
            // 如果分配空间失败,则返回 0
            return 0;
        } else {
            // 如果分配空间成功,则遍历常量字符串中的每个字符,依次赋给串 str
            c = ch;
            for (int i = 0; i <= len; i++) {// 之所以在循环条件中使用 <=。是为例将常量字符串最后的 '\0' 字符也复制到新串中作为结束标记
                str->ch[i] = *(c + i);// 其实也可以使用 str->ch[i]=c[i];
            }
            str->length = len;
            return 1;
        }
    }
}

int compare(String s1, String s2) {
    int i = 0;
    while (i < s1.length && i < s2.length) {
        if (s1.ch[i] != s2.ch[i]) {
            return s1.ch[i] - s2.ch[i];
        }
        i++;
    }
    return s1.length - s2.length;
}

int main() {
    String str;

    // 赋值操作,将一个常量字符串赋给一个串
    printf("\n赋值字符串:\n");
    assign(&str, "hello world");
    printf("%s\n", str.ch);

    // 比较两个串
    printf("\n比较两个串:\n");
    String str2;
    assign(&str2, "hellx world!");
    int cmp;
    cmp = compare(str, str2);
    printf("%d\n", cmp);
}

执行结果是:

赋值字符串:
hello world

比较两个串:

Process finished with exit code -1073740940 (0xC0000374)

原因

代码没有任何问题。这段代码的意思是当传入的 str 串存在(不为 NULL)时那么就释放其空间,然后将指针指向 NULL。但是在 main 函数中我们是直接声明了一个 String str 就作为参数进行传入了,对于结构体 String 中的属性并没有初始化,需要将 str->ch 初始化为 NULL,否则在经过这条语句时,就会出现打不开对应内存地址的报错。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

解决

在 main 方法中声明 String 类型变量使用时,对其进行初始化:

int main(){
	String str;
	str.ch=NULL;
	str.length=0;
}

我们可以写一个初始化函数 init 来初始化声明的串:

/**
 * 初始化串
 * @param str 未初始化的串
 */
void init(String *str) {
    str->ch = NULL;
    str->length = 0;
}

int main(){
	String str;
	init(&str);
}

正确代码

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char *ch;
    int length;
} String;

/**
 * 初始化串
 * @param str 未初始化的串
 */
void init(String *str) {
    str->ch = NULL;
    str->length = 0;
}

int assign(String *str, char *ch) {
    // 0.参数校验,如果 str 中已有字符,那么释放原串空间,因为我们会给它重新分配空间
    if (str->ch) {
        free(str->ch);
        str->ch = NULL;
    }

    // 1.统计常量字符串 ch 中的字符个数,只有知道它的字符个数,我们才能清楚为 str 分配多少个字符空间
    // 局部变量,存储常量字符串 ch 中的字符个数
    int len = 0;
    // 注意,我们不能直接操作 ch,因为是一个指针变量,在下面的操作后我们会移动指针,会修改掉 ch 原本的值,后面如果需要再使用就不是传入的参数值,所以要创建一个临时局部变量引用它的值来进行操作
    char *c = ch;
    // 从头到尾扫描常量字符串,以结束标记 '\0' 作为循环结束条件
    while (*c != '\0') {
        // 计数器加一
        len++;
        // 指针加一,继续下一个字符
        c++;
    }

    // 2.为串 str 分配空间并赋值
    // 2.1 如果常量字符串长度为 0,那么串 str 也该为一个空串
    if (len == 0) {
        str->ch = NULL;
        str->length = 0;
        return 1;
    }
        // 2.2 如果常量字符串长度不为 0,那么将常量字符串中所有字符赋给串 str
    else {
        // 给串分配 len+1 个存储空间,多分配一个空间是为了存放 '\0' 字符
        str->ch = (char *) malloc(sizeof(char) * (len + 1));
        // 判断是否分配空间成功
        if (str->ch == NULL) {
            // 如果分配空间失败,则返回 0
            return 0;
        } else {
            // 如果分配空间成功,则遍历常量字符串中的每个字符,依次赋给串 str
            c = ch;
            for (int i = 0; i <= len; i++) {// 之所以在循环条件中使用 <=。是为例将常量字符串最后的 '\0' 字符也复制到新串中作为结束标记
                str->ch[i] = *(c + i);// 其实也可以使用 str->ch[i]=c[i];
            }
            str->length = len;
            return 1;
        }
    }
}

int compare(String s1, String s2) {
    int i = 0;
    while (i < s1.length && i < s2.length) {
        if (s1.ch[i] != s2.ch[i]) {
            return s1.ch[i] - s2.ch[i];
        }
        i++;
    }
    return s1.length - s2.length;
}

int main() {
    String str;
    init(&str);

    // 赋值操作,将一个常量字符串赋给一个串
    printf("\n赋值字符串:\n");
    assign(&str, "hello world");
    printf("%s\n", str.ch);

    // 比较两个串
    printf("\n比较两个串:\n");
    String str2;
    init(&str2);
    assign(&str2, "hellx world!");
    int cmp;
    cmp = compare(str, str2);
    printf("%d\n", cmp);
}

执行结果如下:

赋值字符串:
hello world

比较两个串:
-9

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值