You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现strShiftLeft函数触发zsh: bus error问题排查求助

字符串左移函数引发总线错误/段错误的排查与修复

问题描述

实现了C语言函数char* strShiftLeft(char* str, int n),功能是将字符串左移n位(把前n个字符移到末尾),例如调用strShiftLeft("Thomas", 2)应返回"omasTh"。但编译运行后,Mac终端出现zsh: bus error ./a.out,在线编译器触发段错误,定位到两处写内存的代码疑似出错:

*(temp - n) = *(temp); 
*(temp + i) = *(temp_arr+i);

原代码

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

char* strShiftLeft(char* str, int n)
{

    // 如果传入字符串为NULL,返回NULL
    if (str == NULL)
    {
        printf("NULL!\n");
        return NULL;
    }

    // 计算字符串长度
    int len = 0;
    char* counter_ptr = str;
    while (*counter_ptr != '\0')
    {
        len++;
        counter_ptr++;
    }

    printf("len: %d\n", len);

    // 如果n大于字符串长度,返回NULL
    if (n > len)
    {
        printf("n too big!\n");
        return NULL;
    }

    // 创建临时数组存储前n个字符,后续追加到字符串末尾
    char temp_arr[n];
    for (int i = 0; i < n; i++)
    {
        *(temp_arr + i) = *(str + i);
    }

    printf("temp_arr = %s\n", temp_arr);
    printf("str is still: %s\n", str);

    char* temp = str + n;
    printf("len - n = %d\n", len - n);

    // 更新字符串前(len - n)个字符(例如n=2时,"Thomas" -> "omasas")
    for (int i = 0; i < (len - n); i++)
    {
        printf("*temp = %c\n", *temp);
        printf("*(temp - n) = %c\n", *(temp - n));

        *(temp - n) = *(temp); // 疑似错误行
        temp++;
    }

    temp = str + (len - n);
    for (int i = 0; i < n; i++)
    {
        *(temp + i) = *(temp_arr+i); // 疑似错误行
    }

    return str;
}

int main()
{
    char* str = strShiftLeft("Thomas", 2);
    printf("%s\n", str); // 预期输出 "omasTh"

    return 0;
}

错误原因

  1. 字符串字面量不可修改:main函数中传入的"Thomas"是字符串字面量,C标准规定字符串字面量存储在只读数据段,任何试图修改它的操作都会触发内存访问错误(段错误/总线错误),这是两处写内存代码出错的根本原因。
  2. temp_arr未加终止符:temp_arr是局部字符数组,只复制了n个字符但没有添加'\0',执行printf("temp_arr = %s\n", temp_arr)时会越界读取内存,导致未定义行为。

修复方案(符合限制要求)

关键点修改

  • 将字符串字面量复制到可修改的栈数组中,再传入函数。
  • 给temp_arr添加字符串终止符,避免printf越界。

修改后的完整代码

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

char* strShiftLeft(char* str, int n)
{
    if (str == NULL)
    {
        printf("NULL!\n");
        return NULL;
    }

    // 计算字符串长度(不使用strlen)
    int len = 0;
    char* counter_ptr = str;
    while (*counter_ptr != '\0')
    {
        len++;
        counter_ptr++;
    }

    printf("len: %d\n", len);

    if (n > len)
    {
        printf("n too big!\n");
        return NULL;
    }

    // 临时存储前n个字符,并添加终止符
    char temp_arr[n + 1]; // 多留一个位置存'\0'
    for (int i = 0; i < n; i++)
    {
        *(temp_arr + i) = *(str + i);
    }
    *(temp_arr + n) = '\0'; // 添加字符串终止符

    printf("temp_arr = %s\n", temp_arr);
    printf("str is still: %s\n", str);

    char* temp = str + n;
    printf("len - n = %d\n", len - n);

    // 左移(len - n)个字符
    for (int i = 0; i < (len - n); i++)
    {
        *(temp - n) = *(temp);
        temp++;
    }

    // 追加前n个字符到末尾
    temp = str + (len - n);
    for (int i = 0; i < n; i++)
    {
        *(temp + i) = *(temp_arr + i);
    }
    // 确保字符串末尾的终止符不变(原字符串已有,此处可省略,但显式写更安全)
    *(str + len) = '\0';

    return str;
}

int main()
{
    // 将字符串字面量复制到可修改的栈数组中
    char str[] = "Thomas";
    char* result = strShiftLeft(str, 2);
    printf("%s\n", result); // 输出 "omasTh"

    return 0;
}

验证说明

修改后运行程序,会正确输出omasTh,且不会触发内存错误:

  • 栈数组str是可写的,函数中对它的修改合法。
  • temp_arr添加了'\0',printf输出时不会越界。

内容的提问来源于stack exchange,提问作者sungenchuang7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 00:55:13