C 我不能在字符数组上设置空终止吗?
我正在尝试创建一个小函数,以在两个标记之间获取字符串。但是我在C 我不能在字符数组上设置空终止吗?,c,C,我正在尝试创建一个小函数,以在两个标记之间获取字符串。但是我在str[len-3]='\0'上得到一个segfault 是否不能在传递的字符串中添加空终止符,然后将指针发回 更改指针的索引而不是将其复制到缓冲区并发送回是一种不好的做法吗 我是否从3个从未释放的字节中得到内存泄漏 /* format for a message <m>Hello world!</>13594750394883323106 <m>"msg"</>
str[len-3]='\0'上得到一个segfault代码>
是否不能在传递的字符串中添加空终止符,然后将指针发回
更改指针的索引而不是将其复制到缓冲区并发送回是一种不好的做法吗
我是否从3个从未释放的字节中得到内存泄漏
/*
format for a message
<m>Hello world!</>13594750394883323106
<m>"msg"</><checksum>
*/
//returns the string beetween tags
char *GetMessage(char *str) {
int len = strlen(str);
for (int i = 0; i < len; i++) {
if (str[i] == '<' && str[i + 1] == 'm' && str[i + 2] == '>') {
if (str[len - 3] == '<' && str[len - 2] == '/' && str[len - 1] == '>') {
str[len - 3] = '\0';
return &str[3];
}
}
}
return NULL;
}
/*
消息格式
你好,世界!13594750394883323106
“味精”
*/
//返回标记之间的字符串
char*GetMessage(char*str){
int len=strlen(str);
对于(int i=0;i
为了更好地对此进行推理,让我们绘制字符串的内存布局。如果我没弄错的话,它是这样的:
111111
0123456789012345...
-> xxxxx<m>Hi</>yyy...\0
fullmessage = "xxxx<m>Hi</>yyyyy";
m = fullmessage;
l = 0;
/* skip until you find a '<m>' tag */
while (m[0] != '\0' && ((l=GetMessage(m)) == 0) m++;
/* l can be 0 here if there was no message in the string */
if (l>0) printf("msg = %.*s",l,m+3);
当然,您不能执行fullmsg=GetMessage(fullmsg)
,否则可能会发生奇怪的事情(内存泄漏最少:)
当您找到
标签时,您的情况是:
111111
0123456789012345...
str -> xxxxx<m>Hi</>yyy...\0
^ ^
i len
111111
0123456789012345...
str -> xxxxx<m>Hi</>yyy...\0
^ ^ ^
i j len
因此,当您找到消息的结尾时,您的情况是:
111111
0123456789012345...
str -> xxxxx<m>Hi</>yyy...\0
^ ^
i len
111111
0123456789012345...
str -> xxxxx<m>Hi</>yyy...\0
^ ^ ^
i j len
现在,当您要打印邮件时,可以执行以下操作:
111111
0123456789012345...
-> xxxxx<m>Hi</>yyy...\0
fullmessage = "xxxx<m>Hi</>yyyyy";
m = fullmessage;
l = 0;
/* skip until you find a '<m>' tag */
while (m[0] != '\0' && ((l=GetMessage(m)) == 0) m++;
/* l can be 0 here if there was no message in the string */
if (l>0) printf("msg = %.*s",l,m+3);
fullmessage=“xxxxHiyyyyy”;
m=完整消息;
l=0;
/*跳过,直到找到“”标记*/
而(m[0]!='\0'&((l=GetMessage(m))==0)m++;
/*如果字符串中没有消息,则此处的l可以为0*/
如果(l>0)printf(“msg=%.*s”,l,m+3);
我没有完全测试它,但我希望您能理解。您在str[len-3]='\0';
上遇到崩溃,因为您试图写入只读位置。用作值的字符串文本可以放在只读存储中,试图修改它们会调用未定义的行为
不能将常量字符串传递给此函数
GetMessage("<m>Hello world!</>");
代码中有一个错误:return&str[3];
应该是return&str[i+3];
此外,您的代码不会处理注释中的示例,因为
子字符串不在末尾
以下是一个简化版本:
#include <string.h>
char *GetMessage(char *str) {
str = strstr(str, "<m>");
if (str != NULL) {
str += 3;
char *p = strstr(str, "</>");
if (p != NULL)
*p = '\0';
}
return str;
}
#包括
char*GetMessage(char*str){
str=strstrstr(str,“”);
如果(str!=NULL){
str+=3;
char*p=strstrstr(str,“”);
如果(p!=NULL)
*p='\0';
}
返回str;
}
请注意,GetMessage()
返回的指针指向参数字符串内部。您不能将其传递到free()
以取消分配字符串,这将调用未定义的行为。只有malloc()
返回的原始值才能传递到free()
以继续回答问题
(一)
是否不可能在传递的字符串中添加nulltermination,然后返回指针
事实证明,在本例中,作为文本传递的字符串是问题所在。在评论中指出了这一点,这正是我测试函数的方式
GetMessage("<m>Hello world!</>");
(二)
更改指针的索引而不是将其复制到缓冲区并发送回是一种不好的做法吗
这似乎是首选。但不应该引起任何问题
(三)
我从3个字节中得到了一个内存泄漏,但从未释放
/*
format for a message
<m>Hello world!</>13594750394883323106
<m>"msg"</><checksum>
*/
//returns the string beetween tags
char *GetMessage(char *str) {
int len = strlen(str);
for (int i = 0; i < len; i++) {
if (str[i] == '<' && str[i + 1] == 'm' && str[i + 2] == '>') {
if (str[len - 3] == '<' && str[len - 2] == '/' && str[len - 1] == '>') {
str[len - 3] = '\0';
return &str[3];
}
}
}
return NULL;
}
这真是太好了
感谢所有的投入 return&str[3]代码>->返回str+3没有看到释放分配给字符串的内存的代码,我们只能猜测。是否有软件告诉您内存泄漏?如果是这样,你能给我们看一下消息吗?为什么它返回str+3
?。它是否应该返回str+i+3
?查看此函数的调用方式会很有用。可能是您正在向此函数传递字符串文本,并且无法可靠地修改字符串文本-它经常崩溃(尽管行为未定义,并且可能会发生比崩溃更糟糕的事情)。为什么您认为作为参数传递的字符串是只读的?你在附近工作吗?你就是那个把问题交给雅各布的人吗???参数字符串被定义为char*
,而不是const char*
,因此更改原始字符串并不违法,IMHO@LuisColorado当前位置我从雅各布的评论中了解到这一点:我不知道。我只是用一条GetMessage(“Hello world!”)调用这个函数;当我遇到问题的时候。但这就是原因。所编写的代码并不非法,但它确实假设参数字符串是可修改的,而字符串文本则不是。遗憾的是,编译器在默认情况下不会抱怨const
限定不匹配。以更高的警告级别(即gcc-Wall-W
或等效级别)调用编译器将产生有用的诊断消息。。。当我发表这样的评论时,我总是很讽刺。别把我当回事。我同意你说的那句话,遗憾的是编译人员什么也没说。但这也让人想起了可编译的旧遗留代码。很好的解释!祝贺