【问题标题】:How to fix 'strtok destroy original string' in c如何在c中修复'strtok破坏原始字符串'
【发布时间】:2023-03-05 03:34:02
【问题描述】:

我正在为汇编程序编写编译器,我需要对从文件中获取的文本进行解析,而不对原始字符串进行任何更改。我用来复制字符串的函数是strcpy到缓冲区,剪切字符串的函数是strtok剪切缓冲区。 一切都很完美,但是一旦我在使用函数 addressingConstantIndex 后尝试剪切原始字符串,我就会得到 null

我试图将缓冲区的类型更改为字符指针,但它并没有真正起作用。我猜主要问题在于我将原始字符串复制到缓冲区的方式。

int main(){
    char desti[MAXCHAR];
    char *temp;
    char *token;
    temp = "mov LIST[5] , r4";
    strcpy(desti,temp);
    printf("\ndest is : %s\n", desti);

    token = strtok(desti," ");

    printf("\nthe Token in Main is : %s \n", token);

    token = strtok(NULL, ",");

    printf("\nthe Token in Main is : %s\n", token);

    printf("\nThe value is %d \n ",addressingConstantIndex(token));

    token = strtok(NULL, " ,");

    printf("\nthe Token in Main is : %s\n", token);
    return 0;
}



int addressingConstantIndex(char * str) {
    char buf[43];
    char *token;
    int ans;
    strcpy(buf, str);
    token = strtok(buf, "[");
    printf("The string is %s\n",str);
    if (token != NULL)
    {
        printf("the token is %s\n", token);
        token = strtok(NULL, "]");
        printf("the token is %s\n", token);
        if(isOnlyNumber(token))
        {
            token = strtok(NULL, " ");
            if (checkIfSpaces(token,0) == ERROR)
            {
                printf("ERROR: Extra characters after last bracket %s \n", str);
                ans = ERROR;
            } else
                ans = OK;
        } else {
            printf("ERROR: Unknown string - %s  - its not a macro & not a number.\n", token);
            ans = ERROR;
        }
    } else {
        printf("ERROR: %s , its not a LABEL", token);
        ans = ERROR;
    }
    return ans;
}


int isOnlyNumber(char *str) {
    int i, isNumber;
    i = 0;
    isNumber = 1;
    if (!isdigit(str[i]) && !(str[i] == '-' || str[i] == '+'))
    {
        isNumber = ERROR;
    }
    i++;
    while (i < strlen(str) && isNumber == 1)
    {
        if (!(isdigit(str[i]))) {
            if (isspace(str[i]))  
                isNumber = checkIfSpaces(str, i);
            else
                isNumber = ERROR;
        }
        i++;
    }
    return isNumber;
}


int checkIfSpaces(char *str, int index) {
    int i;
    if (str == NULL)
    {
        return OK;
    } else {
        for (i = index; i < strlen(str); i++)
        {
            if (!isspace(str[i])) return ERROR;
        }
    }
    return OK;
}




预期结果:

dest is : mov LIST[5] , r4

the Token in Main is : mov

the Token in Main is : LIST[5]
The string is LIST[5]
the token is LIST
the token is 5

The value is 1

the Token in Main is : r4

真实结果:

dest is : mov LIST[5] , r4

the Token in Main is : mov

the Token in Main is : LIST[5]
The string is LIST[5]
the token is LIST
the token is 5

The value is 1

the Token in Main is : (null) 

区别在结果的最后一行。

【问题讨论】:

  • 如果您需要保留原始字符串,请复制该字符串并在副本上使用strtok(),或者不要使用strtok()
  • 另请注意,您不能使用strtok() 同时分析两个不同的字符串。基本上,strtok() 通常是错误的函数使用;这是错误功能的许多次之一。请改用strspn()strcspn()
  • 我需要对我得到的字符串的每个部分做一些验证。
  • 你的平台有strtok_r吗?

标签: c string strtok


【解决方案1】:

问题在于strtok() 维护一个指向当前字符串位置的静态指针。所以在addressingConstantIndex() 中,你开始处理本地的buf,这样当你返回main() 时,它不再解析desti,而是现在超出范围的buf 来自addressingConstantIndex()

对现有代码的最简单更改是使用strtok_r()(或Windows 上的strtok_s()):

char* context = 0 ;
token = strtok_r( desti, " ", &context ) ;
printf("\nthe Token in Main is : %s \n", token);
token = strtok_r( NULL, ",", &context ) ;
...

然后同样在addressingConstantIndex():

char* context = 0 ;
token = strtok_r(buf, "[", &context);
...

【讨论】:

    【解决方案2】:

    strtok 在每次调用时将字符串中的分隔符替换为 NULL。您的代码在主级别查找“LIST[5]”标记,此时它已将“,”替换为 NULL。

    addressingConstantIndex 中,strtok 使用新字符串重置并正确解析(尽管您的函数类型为 void 而不是 int)。

    再次在主级别,strtok 没有被重置,因此它继续解析 addressingConstantIndex 中使用的字符串。

    要解决此问题,您需要再次重置 strtok 才能继续。但是,您不能只使用 strtok(desti,",") 调用它,因为 desti 将之前调用的所有分隔符设置为 NULL。

    一个快速的解决方案是将令牌复制到主级别的addressingConstantIndex,并在下一个级别解析之前完成主级别。

    int main(){
        char desti[MAXCHAR];
        char *temp;
        char *token;
        temp = "mov LIST[5] , r4";
        strcpy(desti,temp);
        printf("\ndest is : %s\n", desti);
    
        token = strtok(desti," ");
        printf("\nMnemonic : %s \n", token);
    
        token = strtok(NULL, ",");
        printf("\nLIst bit: %s\n", token);
    
        char buf[80];       //Save the token 
        strcpy(buf, token);
    
        token = strtok(NULL, " ,"); //Finish this level of processing
        printf("\nRegister: %s\n", token);
    
        //Continue at the next level with copy
        printf("\nThe value is %d \n ",addressingConstantIndex(buf)); 
        return 0;
    }
    

    尽管strtok_r 解决方案可能会更好地满足您的需求

    【讨论】:

      猜你喜欢
      • 2022-07-29
      • 1970-01-01
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 2015-06-28
      相关资源
      最近更新 更多