第一个代码(正确): void LogPrint(const char *msg) { char buffer[120]; memset(buffer, 0, sizeof(buffer)); sprintf(buffer,”%s”,msg); strcat(buffer, “\r\n”); write_log_file(“/usr/log.txt”, FILE_MAX_SIZE, buffer, strlen(buffer)); } 第二个代码(段错误): void LogPrint(const char *msg) { char *buffer; buffer = msg; strcat(buffer, “\r\n”); write_log_file(“/usr/log.txt”, FILE_MAX_SIZE, buffer, strlen(buffer)); } 有时候会突然搞不懂C语言的指针, 请问, 我第二个代码 为什么会出现 段错误? 理论上 buffer = msg; 也是赋予指针 buffer 一个实际地址吧? |
|
#1 |
具体怎么调用的,从所给的代码中看不出来。
第二个代码中msg是用const修饰的,然后又用buffer赋值,最后调用了strcat,这里本身就有问题。相当于是把const修饰的指针,最后进行了修改,这明显是语义上的错误 |
#2 |
你的意思是 第二个代码中 形参 去掉 const 就不会报错了?
我觉得 buffer = msg; 这句代码本身很别扭,应该是有问题,但是我又说不出具体原因。 |
#3 |
回复2楼: 这么用,没有问题,语法上允许。我指的是,“语义”上是不对的。关键是看调用端是怎么传入参数引起的崩溃 |
#4 |
亲,很高兴为你解答这个问题。
char *buffer; 此时的字符指针是没有内存空间的,是一个错误的指针 char buffer[20]; 这是有内存空间的 buffer = msg;当将数据赋值给数组时,是直接将msg数据复制到buffer,比如buffer数组的首地址是123456 msg的指针地址是654321,那么此时123456的数据就是msg的数据 而当buffer = msg;当将数据赋值给指针时,是直接将msg数据复制到buffer,而现在的buffer指针是一个错误的 指针,那么当然就会出错。 *buffer = *msg; 这样的话就可以让buffer指针批向msg,也就是说msg地址是654321,那么赋值之后buffer也是654321 这样是可以的。 当然你在申请buffer指针时就分配了内存空间的话就可以使用这样的赋值了:buffer = msg; |
#5 |
回复3楼: 前端调用的话,就是 把字符串作为参数: LogPrint(“hello, world”); 或者: char info[] = “hello,world”; LogPrint((char *)info); 类似这样吧。 |
#6 |
回复4楼: 光高兴没有用,说得正确才行。 char *buffer; 此时的字符指针是没有内存空间的,是一个错误的指针 ————— 指针还有错误的?指针是完整的对象类型,buffer本身是一个对象,你怎么说它没有内存空间?! buffer = msg;当将数据赋值给数组时,是直接将msg数据复制到buffer,比如buffer数组的首地址是123456 ————— 这真是可怕,没听说过指针赋值会将指针所指向的数据复制过去的。即使是数组之间赋值也是不允许的。指针msg和buffer都是对象,将msg的值赋给buffer难道有错? |
#7 |
回复4楼: 多谢你的分析。 我原先理解的是:比如: char *p; char i = 1; p = &i; 于是 p 就指向了 i p 存的是 i 的地址; 类似的… char *buffer; buffer = msg 我的理解是 msg 是一个字符串的首地址, 那么 buffer 也就等于 字符串的首地址, 相当于有了内存空间; 而你的意思是 ,*buffer = *msg 才能使 buffer 等于 msg 所指向的地址? |
#8 |
回复7楼: 你把const去掉试一下不就知道了? |
#9 |
2楼得解释我还支持,4楼。解释错了吧
|
#10 |
回复5楼: LogPrint(“hello, world”);调用第二个函数 与 char info[] = “hello,world”; LogPrint((char *)info); 调用第二个函数,结果是不一样的 LogPrint(“hello, world”)中的”hello, world”字符串,分配在常量区,是不能进行写操作的。 而char info[] = “hello,world”;是分配在栈区,可以进行可操作。 所以,第一种调用会崩溃,第二种正常。 |
#11 |
const char* 无法分配的char* 编译都过不了吧
|
#12 |
const const。
|
#1315分 |
第一个逻辑和写法都正确
第二个逻辑错误 因为你只是想 log msg 而已(把字符串msg,写到文件中),并不想修改 msg 这块内存中的任何内容。 buffer = msg 二者指向同一位置(指针的值相同,表示同一地址,而且类型也几乎相同,只有可写与不可写的区别) strcat(buffer, “\r\n”); 向msg 后面添加 “\r\n” 回车换行符, 这和这段程序的逻辑严重背离 从参数看 const char * msg 表示不希望修改字符串msg的内容 从 buffer = msg strcat(buffer, “\r\n”); 看 又修改了字符串msg 的内容 代码的逻辑是有问题的 上面这个逻辑错误,是程序本身的功能设计错误 不符合,这段程序要实现的目标,不是报错的直接原因 至于出现段错误,是因为 msg 对应的实参本身,指向的内容,也是不可改写,例如是个字符串字面值(串常量), 这种数据,有时候会分配在只读区(段),所以就会在运行时,报出段错误。 C参数传递,不论是指针,还是其他数据,都是值传递,实参复制(可能有类型提升等情况)到形参中 但是传递指针,我们可以修改 指针指向的内容,因为这个 实参和形参指向同一个位置。 这是指针的性质,功能,和C的参数传递无关。 |
#14 |
第一段程序,唯一有点小问题的地方是,如果 msg 太长,会出现错误
|
#15 |
void LogPrint(const char *msg) //msg 指向代码段 只读 | (可能,具体看你调用情况,msg分配足够内存) { char *buffer; buffer = msg; strcat(buffer, "\r\n"); write_log_file("/usr/log.txt", FILE_MAX_SIZE, buffer, strlen(buffer)); } |
#16 |
回复7楼: msg是一个对象,它的值是一个字符串的首地址。buffrt=msg后,buffer对象的值也是那个字符串的首地址。 *buffer=*msg的功能等效于buffer[0]=msg[0] |
#17 |
回复7楼: 是这个意思,而如果char *buffer在没有new一个新的内存空间一般在VC下面默认是0xCCCCCCC这些地址等等,所以你在使用这个地址的时候会出错,而如果你要使用buffer = msg的话,那么buffer就得指向一个正确的用户空间地址。 |
#18 |
回复17楼: 另外一个问题应该我说错了,buffer = msg,当buffer是数组是,是将msg数据移动到buffer,类似于文件剪贴,而不是复制,其它的我还是坚持我的看法。 |
#19 |
两份代码语法都没有问题, 问题应该是你传的实参,你应该是传的常量字符串做实参, 所以第一份代码没有问题,后面的strcat将添加的字符串写入了buff内存中, 第二段代码 传常量字符串时,strcat会将字符写入了常量字符串后面的内存中, 这就会造成内存越界报段错误 推荐第一份代码 |
#20 |
回复18楼: 先回去学习学习吧 |
#21 |
這個帖子怎麼越看越瘆的慌
|
#225分 |
LogPrint(“hello, world”);
调用第二种LogPrint,导致strcat修改常量区的内存,出错 char info[] = “hello,world”; LogPrint((char *)info); 调用第二种LogPrint,导致strcat虽然修改的是栈上内存,但是会越界,这种行为是危险的 |
#23 |
确实是我忽略了 常量字符串 是在只读区域,
现在明白了,多谢大家! |
#24 |
回复22楼: char info[] = “hello,world”; LogPrint((char *)info); 我试了一下,确实 有 越界 提示: *** stack smashing detected ***: ./sdata terminated |
#25 |
第一个程序,唯一有问题的是msg 不确定多长,
所以可能会有安全问题,(缓冲区溢出)。 但从逻辑上看,不是错误,只是没有考虑代码安全。 早期,这种代码很多。 第二个程序,直接就是逻辑错误。 某些情况下,会导致运行时错误, 但是并不是所有编译器,都能保证运行时错误的,起码早期的不会。 |
#26 |
char *buffer没有指定指向是很危险的,最好先char *buffer = null,后面再分配内存
|