未经处理的异常:0xC0000005:读取/写入位置冲突——从去掉字符串所有空格说起

本文通过实例解析了C/C++编程中因不当修改字符串常量引发的0xC0000005错误,并提供了正确处理字符串的方法。

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

转自:http://www.typecodes.com/cseries/trimspace0xC0000005.html

        在c/c++中,有时会遇到 c0xC0000005: 读取/写入位置冲突的问题。明明编译器编译通过,但是在执行的时候就出现 Segmentation fault(coredump) 了。该错误是由于内存访问出错引起的,最常见于指针的错误使用和数组越界等。下面是博主之前的一个经历——去掉一个字符串前后的所有空格。

char * pcontent = "  abcdef  "; //待去掉前后空格的字符串
char * p = NULL;

/* 1去除后面的空格 */
p = pcontent + strlen( pcontent ) - 1;  //指针p指向字符串的末尾
while( *p == 0x20 )
{
    p--;
}
*(p+1) = 0x00;  //将字符串中‘f’后面的一位空格改成结束符号'\0'
printf( "Line=[%d], pcontent=[%s]\n", __LINE__, pcontent );


咋一看,思路挺对的,遍历字符串后面的所有空格,然后只要将字符串中‘f’后面的一位空格改成字符串结束符即可。遗憾的是出现了 Segmentation fault(coredump) ,用Vs调试,程序执行到断点 *(p+1) = 0x00; 时,出现未经处理的异常: 0xC0000005 写入冲突。


调用内存和堆栈可以看到地址 0x001b5764 里面的元素是 0x20,表示空格。


为什么把字符串结束符号'\0'写入到地址 0x001b5764 中就出错呢?原因是:定义指针pcontent的时候,语句 char * pcontent = " abcdef " 中的字符串是一个常量 " abcdef "。常量在内存中是不可以被改写的,所以执行 *(p+1) = 0x00; 就会出现 未经处理的异常: 0xC0000005: 写入位置冲突 。

另外,对于内存中的 0x00000000 地址,不能执行读取和写入操作。例如前面的 char * p = NULL; 这种指针初始化(避免成为野指针)操作,在后面不能直接来一个 printf("%c", *p) ,否则就会出现错误 未经处理的异常:0xC0000005:读取位置0x00000000时发生冲突 。

知道原理后,改成正确的去掉一个字符串前后的所有空格的程序:

/**
 * @FileName :  trimallspace.c
 * @Author   :  vfhky http://www.typecodes.com 20140725
 * @Functions:  去掉字符串前后所有的空格
*/
#include <string.h>
#include <stdio.h>
int main()
{
    char * p = NULL;
    char ccontent[20] = "  abcdef  ";   //把字符串放进一个数组而不是成为常量
    printf( "Line=[%d], ccontent=[%s]\n", __LINE__, ccontent );

    /* 1去除后面的空格 */
    p = ccontent + strlen( ccontent ) - 1;
    while( *p == 0x20 )
    {
        p--;
    }
    *(p+1) = 0x00;
    printf( "Line=[%d], pcontent=[%s]\n", __LINE__, p );

    /* 2去除前面的空格 */
    p = ccontent;   //重置指针变量p的位置
    while( *p == 0x20 )
    {
        p++;
    }
    printf( "Line=[%d], p=[%s]\n", __LINE__, p );
    return 0;
}


#include <reg51.h> #include <intrins.h> #define LCD_PORT P0 // LCD数据总线 sbit RS = P2^4; // LCD寄存器选择 (0=指令, 1=数据) sbit EN = P2^6; // LCD使能端 sbit DQ = P1^1; // DS18B20数据线 unsigned char j; // 毫秒级延时函数 void delay_ms(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) for (j = 0; j < 125; j++); // 12MHz晶振下约1ms } // LCD写入命令 void LCD_Command(unsigned char cmd) { RS = 0; // 选择指令寄存器 LCD_PORT = cmd; // 发送命令 EN = 1; // 使能脉冲 _nop_(); _nop_(); _nop_(); // 延时确保脉冲宽度 EN = 0; delay_ms(2); // 命令执行延时 } // LCD写入数据 void LCD_Data(unsigned char dat) { RS = 1; // 选择数据寄存器 LCD_PORT = dat; // 发送数据 EN = 1; _nop_(); _nop_(); _nop_(); EN = 0; delay_ms(1); // 数据写入延时 } // LCD初始化函数 void LCD_Init() { delay_ms(20); // 上电延时等待稳定 // 初始化序列 (8位模式) LCD_Command(0x38); // 8位数据, 双行显示, 5x7点阵 LCD_Command(0x0C); // 开显示, 关光标, 无闪烁 LCD_Command(0x06); // 地址自动递增, 无显示移位 LCD_Command(0x01); // 清屏 delay_ms(5); // 清屏需要额外延时 } // 显示字符串 void LCD_Write_String(unsigned char *str) { while (*str) { LCD_Data(*str); // 逐字符显示 str++; } } // 显示整数 (0-999) void LCD_Write_Num(int num) { unsigned char digits[3]; unsigned char i = 0; // 处理百位数 if (num > 99) { digits[i++] = num / 100 + '0'; num %= 100; } // 处理十位数 if (num > 9 || i > 0) { digits[i++] = num / 10 + '0'; } // 处理个位数 digits[i++] = num % 10 + '0'; // 显示数字 for (j = 0; j < i; j++) { LCD_Data(digits[j]); } } // 主程序 void main() { const int SP_TEMP = 80; // 目标温度80℃ LCD_Init(); // 显示目标温度 LCD_Command(0x80); // 第一行起始位置 LCD_Write_String("SP: "); LCD_Write_Num(SP_TEMP); LCD_Write_String("C"); while(1) { // 读取DS18B20温度(省略) // LCD_Command(0xC0); // 第二行起始位置 // 显示实时温度的逻辑... } }其中LCD的rw连接c51的p2.5,帮我补充while(1) { // 读取DS18B20温度(省略) // LCD_Command(0xC0); // 第二行起始位置 // 显示实时温度的逻辑... }里面的内容
最新发布
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值