English 中文(简体)
C语言中的字符串解析错误:“左操作数必须是左值”
原标题:
  • 时间:2009-01-28 23:48:35
  •  标签:

我面临着在 ANSI C 中提取格式为“blah.bleh.bloh”的字符串中的信息的需求。通常情况下,我会使用strok()来完成此操作,但是由于我正在通过strtok获取此字符串,并且strtok不是线程安全的,因此我无法使用此选项。

我已经编写了一个手动解析字符串的功能。以下是代码片段:

for(charIndex=0; charIndex < (char)strlen(theString); charIndex++)
{
    if(theString[charIndex] ==  . )
    {
        theString[charIndex] =   ;
        osi_string_copy_n(Info[currentInfoIndex], 1024, theString, charIndex + 1 );
        currentInfoIndex++;
        theString = &theString[charIndex + 1];
    }
    charIndex++;
}

正如您所见,我尝试查找第一个“。”的出现,并记录字符的索引。然后,我将“。”转换为空字符并将第一个字符串复制到一个数组中。

然后我希望将指针更改为在找到分隔符后立即开始,从而为我提供一个新的较短字符串。

很不幸,我在这一行遇到了一个错误:

theString = &theString[charIndex + 1];

错误是:

error C2106:  =  : left operand must be l-value

我为什么不能像这样移动指针?我的方法有缺陷吗?也许有人有更好的方法来解析这个字符串。

编辑:针对评论,theString声明如下:

char theString[1024] = {0};

而且,我保证字符串永远不会超过1024个字符。

最佳回答

在假设你已经将String定义为一个数组的前提下,尝试将其定义为一个指针。 当你将char变量声明为一个数组时,你不能在后面更改它的地址。

我假设你有一个类似于声明的东西

char theString[100];

最简单的解决方案是让那个声明不变,并添加另一个声明:

char *str = theString;

然后在您当前使用theString的任何地方使用str

问题回答

您可以使用strtok_r,该函数在大多数平台上都可用并且是可重入的。这意味着它不保留内部状态,并且您可以在嵌套循环中调用它而不会出现问题。

只有一种真正的C语言方法,那就是使用指针、紧密循环和神秘命令 :-).

以下的getNext()函数将允许您按顺序返回所有组件,然后是NULL哨兵。 您需要提供足够大的缓冲区来存储组件。 我还包括了我的测试程序,以便您可以检查它(如果您愿意,还可以添加更多单元测试用例)。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *getNext (char *pStr, char *pComp) {
    /* Special for  .  at string end. */
    if ((*pStr ==  . ) && (*(pStr+1) ==   )) {
        *pComp =   ;
        return pStr + 1;
    }

    /* Check if no components left. */
    if (*pStr ==   )
        return NULL;

    /* Transfer component one character at a time. */
    while ((*pStr !=   ) && (*pStr !=  . ))
        *pComp++ = *pStr++;
    *pComp =   ;

    /* Skip  .  at end, if there, but not at end of string. */
    if ((*pStr ==  . ) && (*(pStr+1) !=   ))
        pStr++;

    // Return location of next component.
    return pStr;
}

int main (int argCount, char *argVal[]) {
    int argNum;
    int compNum;
    char *newStr;
    char *strPtr;

    if (argCount < 2) {
        printf ("Usage: components <string to componentize>...
");
        return 1;
    }
    for (argNum = 1; argNum < argCount; argNum++) {
        if ((newStr = malloc (strlen (argVal[1]) + 1)) == NULL) {
            printf ("Out of memory for  %s .", argVal[argNum]);
        } else {
            printf ("Input string is  %s .
", argVal[argNum]);
            compNum = 0;
            strPtr = getNext (argVal[argNum],newStr);
            while (strPtr != NULL) {
                printf ("   Component [%3d] is  %s .
", ++compNum, newStr);
                strPtr = getNext (strPtr,newStr);
            }
            free (newStr);
        }
    }

    return 0;
}

这是输出:

[fury]> components your.test.string .dot.at.start at.end. .both. no_dots   
Input string is  your.test.string .
    Component [  1] is  your .
    Component [  2] is  test .
    Component [  3] is  string .
Input string is  .dot.at.start .
    Component [  1] is   .
    Component [  2] is  dot .
    Component [  3] is  at .
    Component [  4] is  start .
Input string is  at.end. .
    Component [  1] is  at .
    Component [  2] is  end .
    Component [  3] is   .
Input string is  .both. .
    Component [  1] is   .
    Component [  2] is  both .
    Component [  3] is   .
Input string is  no_dots .
    Component [  1] is  no_dots .
Input string is   .

变量“theString”必须是指针类型而不是数组类型。

这一行代码theString = &theString[charIndex + 1];本来就不应该存在。即使这行代码没有出现错误并且正常运行,theString[charIndex]也无法成为你所期望的下一个相邻字符,因为theString被移动了。

我的建议是尽可能少的更改代码:

for(charIndex=0; charIndex < strlen(theString); charIndex++)
{
    if(theString[charIndex] ==  . )
    {
        theString[charIndex] =   ;
        osi_string_copy_n(Info[currentInfoIndex], 1024, theString + subStrStart, charIndex + 1 - subStrStart);
        currentInfoIndex++;
        subStrStart = charIndex + 1;
    }
    charIndex++;
}

我不确定您的osi_string_copy_n函数是做什么的,所以这一行只是根据您的原始代码的猜测。但是,如果您正在将子字符串复制到另一个位置,并且在函数参数中指定了子字符串长度,那么应该不需要将子字符串的结尾设为null吗?

Edit:
I found your code has two charIndex++. Is theString double byte string? If it s so, maybe it is more proper to use wchar_t

如果你有一个非古老的libc,你就有strtok_r,它是strtok的可重入变体。

char *saveptr;
char *str;
for (str = strtok_r(theString, ".", &saveptr);
        str;
        str = strtok_r(NULL, ".", &saveptr)
    )
{
    printf("got:  %s 
", str);
}

这保证不会影响到任何由 strtok 保留的状态,也不会影响任何由其他 strtok_r 调用保留的状态(假设它们不共享你的 saveptr )。





相关问题
热门标签