【问题标题】:String manipulation in C results in random string contentC 中的字符串操作导致随机字符串内容
【发布时间】:2020-10-14 21:36:15
【问题描述】:

我正在为必须使用 Flex 的学校做作业。我正在尝试做一些简单的字符串操作,但我遇到了一些我不理解的奇怪结果。下面的代码应该将输入的第二个字母替换为相应的数字。

我的代码:

uid           [a-z][a-z][a-z]+
%%

{uid}   {
                char ID[strlen(yytext)];
                strncat(ID, yytext, 1);
                char comp = yytext[1];
                if (comp=='a'||comp=='j'||comp=='s'){
                  strcat(ID,"1");
                }else if(comp=='b'||comp=='k'||comp=='t'){
                  strcat(ID,"2");
                }else if(comp=='c'||comp=='l'||comp=='u'){
                  strcat(ID,"3");
                }else if(comp=='d'||comp=='m'||comp=='v'){
                  strcat(ID,"4");
                }else if(comp=='e'||comp=='n'||comp=='w'){
                  strcat(ID,"5");
                }else if(comp=='f'||comp=='o'||comp=='x'){
                  strcat(ID,"6");
                }else if(comp=='g'||comp=='p'||comp=='y'){
                  strcat(ID,"7");
                }else if(comp=='h'||comp=='q'||comp=='z'){
                  strcat(ID,"8");
                }else if(comp=='i'||comp=='r'){
                  strcat(ID,"9");
                }
                strncat(ID,yytext+2,strlen(yytext)-2);
                printf("%s\n",ID);
                printf("ID strlen: %d\n",strlen(ID));
                return 1;

上面的代码运行后得到的结果是:

所以我不太确定为什么会得到上述结果,这个结果也不能完全重现,我得到的随机字母和字符总是不同的。我已经查阅了有关如何操作字符串的多个指南,但我无法弄清楚我在一生中做错了什么。第一个输入的结果是正确的,但是我尝试输入的第二个输入会导致无法读取的字符。

【问题讨论】:

  • char ID[strlen(yytext)]; strncat(ID, yytext, 1);。这是未定义的行为,因为strncat 需要一个字符串作为第一个参数,而您拥有的是一个未初始化的缓冲区。
  • 你可能想要char ID[strlen(yytext) + 1]; strncpy(ID, yytext, strlen(yytext) + 1);

标签: c string flex-lexer


【解决方案1】:

C99 可变长度数组 (VLA)

char ID[strlen(yytext)];

不够大,无法容纳完整的yytext。如果一个C字符串s,即strlen(s)的长度是n,那么你需要n+1字节的存储空间。这是因为字符串以空字节结束。

strncat(ID, yytext, 1);

strncat 函数需要有效字符串的参数:以空字符结尾的字符数组。它将字符附加到左参数。但是ID数组还没有初始化。

另一个问题是strncat 函数,就像它的表亲strncpy 一样,不会以空值终止目标缓冲区(除非字符串比指定的n 短。)

这里的一种可能性是执行以下操作之一:

snprintf(ID, 1, "%s", yytext);

sprintf(ID, "%.1s", yytext);

char ID[strlen(yytext)] = ""; // zero-initialize it
ID[0] == yytext[0];           // ID now string of length 1.

我会按照这些思路来写整个事情:

char ID[strlen(yytext)+1];
int comp = yytext[1];
int code = -1;

switch (comp) {
case 'a': case 'j': case 's':
   code = 1;
   break;
// ... similarly for other cases:
}

if (code != -1)
  sprintf(ID, "%c%d%s", yytext[0], code, yytext + 2);
else
  sprintf(ID, "%c%s", yytext[0], yytext + 2);

这个想法似乎只是用数字代码替换第二个字符,或者可能根本没有代码。我们知道ID 足以容纳sprintf 的结果,前提是code 是0 到9 范围内的整数值。

另一种方式是这样的:

  // No ID array required: just clobber yytext!

  switch (yytext[1]) {
  case 'a': case 'j': case 's':
     yytext[1] = '1';
     break;
  // ... similarly for other cases:
  default: // no match: delete yytext[1].
     memmove(yytext + 1, yytext + 2, strlen(yytext + 2) + 1);
     break;
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-20
    • 2014-04-30
    • 2013-10-14
    • 1970-01-01
    相关资源
    最近更新 更多