我不能在 char 数组上设置空终止吗?

标签 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;
}

最佳答案

为了更好地推理这一点,让我们绘制字符串的内存布局。如果我理解正确的话,它是这样的:

                     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("Hi There!")`,你将得到一个核心转储,因为用于引号之间的字符串的内存是只读的。

一个可能的解决方案是稍微改变 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);

我没有完全测试它,但我希望你明白了。

关于我不能在 char 数组上设置空终止吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40094459/

相关文章:

c - 关于 C 中的 printf 格式字符串

在 C 编程中比较两个文件以匹配行

java - 如何将结构数组传递给函数以便在 JNA 中获取结果

c - Y86 1 步停止异常 HLT

使用递归计算像素

c++ - 从 UDP 流读取时 ffmpeg 出错

C 堆栈帧跟踪

c - 处理 pthread 以干净退出

c - 我找到了每个字母的频率,尽管它总是为所有字母返回 0

c - 宏扩展 : should it work? 后重新扫描 'defined' 运算符