我有一串字符,用“ |”分成两组;空间,垂直条/管,空间。字符串“ ACGT”中将永远只有四个字符。我的问题是,如果我使用sscanf或strtok,我可以很好地读取第一个字符串组,但是第二个字符串组只包含该组的第一个字符。

因此,相关剪裁为:

typedef struct {
  char strings[1][399]; // 2D array of the strings
  int length[1]; // Line Length 1 and 2
} DoubleLOT;

char line[1024]; // Each string can only be a max of 400 chars anyway
DoubleLOT inStrings; // structs to hold string sequences

// Init variables
for (a=0;a<=1;a++){
  strcpy(inStrings.strings[a], "");
  inStrings.length[a]=0;
}

strcpy(line, "GAAT | GAAT");


使用sscanf();

sscanf(line, "%[ACGT] | %[ACGT]", inStrings.strings[0], inStrings.strings[1]);
inStrings.length[0]=strlen(inStrings.strings[0]);
inStrings.length[1]=strlen(inStrings.strings[1]);
printf(">%s< %i\n", inStrings.strings[0], inStrings.length[0]);
printf(">%s< %i\n", inStrings.strings[1], inStrings.length[1]);


返回:

>GAAT< 4
>G< 2


使用strtok()如:

strcpy(inStrings.strings[0], strtok(line, " |"));
strcpy(inStrings.strings[1], strtok(NULL, " |"));
inStrings.length[0]=strlen(inStrings.strings[0]);
inStrings.length[1]=strlen(inStrings.strings[1]);
printf(">%s< %i\n", inStrings.strings[0], inStrings.length[0]);
printf(">%s< %i\n", inStrings.strings[1], inStrings.length[1]);


再次返回:

>GAAT< 4
>G< 2


在此示例中,我希望看到:

>GAAT< 4
>GAAT< 4


我试过删除|从“线”字符仍然是同样的问题。我原来有%s而不是%[ACGT],同样的问题。这两个字符串相同的事实对我没有任何帮助,但是一旦解决了问题,我就认为这无关紧要。此外,我还尝试了多种不同的字符串。

我假设这是我正在使用内存或函数如何处理抛出我的内存的事情。我还假设>G< 2在最后指的是\0-我也无法弄清楚它是如何被注入字符串的。对sscanf()之后的“ line”进行检查后发现,它确实仍然完好无损,并且与函数调用之前的“ line”相同–尽管我无法对strtok()进行有意义的操作。

注意:我不在乎是否使用strtok()来补足“ line”;一旦将其分解为两个部分,就完成了。

最佳答案

这里发生的是不确定的行为。您声明您的结构具有一个名为strings的成员,该成员由1个字符乘以399个字符组成;另外一个length是一个整数数组,但超出其范围写入。

您的typedef应该是

typedef struct {
    char strings[2][399];
    int length[2];
} DoubleLOT;


或者,如注释中所述,如果字符串的最大长度为400个字符,则该399应替换为401-400个字符并以'\0'结尾。



但是除此之外,我还可以告诉您平台上正在发生什么以及为什么您确实看到了该输出。

以下结构

typedef struct {
    char strings[1][399]; // 2D array of the strings
    int length[1]; // Line Length 1 and 2
} DoubleLOT;


在普通的LP64架构上,将具有1x399的char数组,后跟1个填充字节,然后是4个对齐的32位整数数组。

现在,当您复制到inString.strings[0]时,只要字符串适合这399个字符,一切都很好。但是写入inString.strings[1]是未定义的行为,因为未分配该内存。但是,在这种情况下,一切似乎都很好,因为写入了字符串"GAAT",以便'G'进入填充字节,并且"AAT"和终止的'\0'将被写在inString.length[0]上。

之后,您写inString.strings[0]的长度; 4在小尾数法中,放入inString.length[0]。字节0x04, 0x00, 0x00, 0x00覆盖字节'A', 'A', 'T' and '\0'

现在inString.strings[1]看起来只有1个字符;第二个是ASCII 4,是不可打印的控制字符。但这是存在的,事实证明strlen(inString.strings[1])是2,而不是1。

最后,在strlen(inString.strings[1])之后,将DoubleLOT inStrings;写在栈/全局变量上的其他地方。

10-04 11:55