我可以不在char数组上设置null终止吗?

时间:2016-10-17 19:46:42

标签: c

我正在尝试创建一个小函数来获取两个标记之间的字符串。但我在str[len -3] = '\0';

上遇到了段错误

是否无法在传递的字符串中添加空终止,然后返回指针?

更改指针索引而不是将其复制到缓冲区并将其发回是不好的做法?

我是否从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;
}

3 个答案:

答案 0 :(得分:3)

为了更好地推理这个问题,让我们绘制字符串的内存布局。如果我得到了正确的话,那就像:

                     111111
           0123456789012345...
        -> xxxxx<m>Hi</>yyy...\0

现在,您希望将指向字符串第一个字符的指针传递给GetMessage()并打印第一条消息。像

这样的东西
fullmsg ="....";
m = fullmsg;
m = GetMessage(m);
printf("msg: %s\n",m);
... // Advance m

当然你不能做fullmsg=GetMessage(fullmsg)或者可能发生奇怪的事情(内存泄漏最少:))。

当您找到<m>标记时,您的情况是:

                     111111
           0123456789012345...
    str -> xxxxx<m>Hi</>yyy...\0
                ^             ^
                i             len

这表明返回str+3并不能达到你想要的效果。您的返回值应为str+i+3

同样地,你应该str[len-3]放置\0。想象一下对GetMessage("x<m>aa</>yzyy")的影响。位置len-3中的字符为z。不是你想要的,我想。

您可以做的是使用另一个索引来查找消息的结尾:

      for (j = i+1; j<len-2; j++) {
        if (str[j] == '<' && str[j+1] == '/' && str[j+2] == '>') {
           // end of message found!!!!
        }
      }

因此,当您找到消息的结尾时,您的情况是:

                     111111
           0123456789012345...
    str -> xxxxx<m>Hi</>yyy...\0
                ^    ^        ^
                i    j        len

我希望我可以告诉你,你可以简单地做str[j]='\0'并返回str+i+3 but, unfortunately I can't. If you do it and pass a literal string ( m = GetMessage(“你好!”)`你会得到一个coredump作为用于字符串之间的字符串的内存引号是只读的。

一种可能的解决方案是稍微改变GetMessage()的语义:

    // returns the length of the message if the string starts with <m>
    int GetMessage(char *str) {
       int len = 0;
       if (str[0]=='<' && str[1]=='m' && str[2]=='>') {
         str += 3;
         while (str[0] != '\0') {
            if (str[0]=='<' && str[1]=='/' && str[2] == '>')
              return len;
            str++;
         }
       }
       return 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);

我没有完全测试它,但我希望你有这个主意。

答案 1 :(得分:1)

您在! pip install pyodbc import pyodbc ImportError: dlopen(/Users/MyUserName/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyodbc.so, 2): Library not loaded: /usr/local/lib/libodbc.2.dylib Referenced from: /Users/MyUserName/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/pyodbc.so Reason: image not found 上遇到崩溃,因为您正在尝试写入只读位置。用作值的字符串文字可以放在只读存储中,尝试修改它们会调用未定义的行为。

您无法将常量字符串传递给此函数。

您的代码中存在错误:str[len-3] = '\0';应为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; } 返回的指针指向参数字符串。您无法将其传递给GetMessage()以取消分配字符串,这将调用未定义的行为。只有free()返回的原始值才能传递给malloc()

答案 2 :(得分:0)

恢复问题的答案。

1) 是不是可以向传递的字符串添加一个nulltermination然后再发送一个指针?

事实证明,在这种情况下,作为文字传递的字符串是问题。 Jonathan Leffler在评论中指出了这一点,这正是我测试函数的方式。

GetMessage("<m>Hello world!</>");

当与没有文字回答的其他功能一起测试时,它运作良好。

GetMessage(ReadSerialData());

2) 更改指针索引而不是将其复制到缓冲区并将其发送回来是不好的做法吗?

这似乎是首选。但不应该引起任何问题。

3) 我从3个字节中得到内存泄漏永远不会被释放?

这非常好解释here

感谢所有的投入!