Ошибка разбора строки в C "левый операнд должен иметь значение l" - PullRequest
3 голосов
/ 29 января 2009

Я столкнулся с необходимостью извлечения информации в строке формата «blah.bleh.bloh» в ANSI C. Обычно я бы использовал strok () для достижения этой цели, но, поскольку я получаю эту строку через strtok, и strtok не является потокобезопасным, я не могу использовать эту опцию.

Я написал функцию для ручного анализа строки. Вот фрагмент:

for(charIndex=0; charIndex < (char)strlen(theString); charIndex++)
{
    if(theString[charIndex] == '.')
    {
        theString[charIndex] = '\0';
        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

Почему мне не разрешено перемещать указатель вот так? Мой метод несовершенен? Возможно, у меня есть идея лучше разобрать эту строку.

РЕДАКТИРОВАТЬ: В ответ на комментарии, объявление для строки является:

char theString[1024] = {0};

Кроме того, я гарантирую, что длина строки никогда не будет превышать 1024 символов.

Ответы [ 6 ]

8 голосов
/ 29 января 2009

В предположении, что вы определили строку как массив, попробуйте определить его как указатель. Когда вы объявляете переменную char как массив, вы не можете позже изменить ее адрес.

Я предполагаю, что у вас есть объявление, похожее на

char theString[100];

Самое простое решение - оставить это объявление в покое и добавить еще одно:

char *str = theString;

и затем используйте str везде, где вы сейчас используете theString.

4 голосов
/ 29 января 2009

Вы можете использовать strtok_r, который доступен на большинстве платформ и является реентерабельным. Это означает, что он не содержит внутреннего состояния, и вы можете без проблем вызывать его из вложенных циклов.

2 голосов
/ 29 января 2009

Существует только один настоящий способ 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) == '\0')) {
        *pComp = '\0';
        return pStr + 1;
    }

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

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

    /* Skip '.' at end, if there, but not at end of string. */
    if ((*pStr == '.') && (*(pStr+1) != '\0'))
        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>...\n");
        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'.\n", argVal[argNum]);
            compNum = 0;
            strPtr = getNext (argVal[argNum],newStr);
            while (strPtr != NULL) {
                printf ("   Component [%3d] is '%s'.\n", ++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 ''.
0 голосов
/ 29 января 2009

Если у вас не-древний libc, у вас есть strtok_r, который является повторным вариантом strtok.

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

Это гарантированно не приведет к сбою ни одного состояния, которое strtok хранит, или любого состояния, которое сохраняют другие вызовы strtok_r (при условии, что они не разделяют ваш saveptr).

0 голосов
/ 29 января 2009

Линия theString = &theString[charIndex + 1]; вообще не должна была существовать. Даже если эта строка не выдает ошибку и работает правильно, theString[charIndex] не будет следующим соседним символом, который вы ожидаете, так как theString перемещается.

Моя рекомендация с почти минимальным изменением кода:

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

Я не уверен, что делает ваш osi_string_copy_n, так что эта строка - всего лишь предположение из вашего исходного кода. Но если вы копируете подстроки в другое место с длиной подстроки, указанной в параметре функции, тогда не нужно обнулять конец подстроки?

Изменить:
Я нашел ваш код имеет два charIndex++. theString двухбайтовая строка? Если это так, возможно, более правильно использовать wchar_t

0 голосов
/ 29 января 2009

Переменная "theString" должна быть указателем, а не типом массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...