scanf - 奇怪的行为:两个连续的调用导致一个不同的字符串和一个正确的字符串

时间:2016-08-27 10:34:18

标签: c string scanf

我在尝试解决this HackerRank problem时遇到了这种行为。该网站使用scanf将格式良好的数据传递给用户的代码。到目前为止,非常好。

p对字符串,每个字符串在一个单独的行上。对于每对,我只需要打印YESNO一次,具体取决于这两个字符串是否具有公共子字符串。毫无疑问,直截了当。但是我没有明显的理由没有通过测试用例。

因此,在使用printf进行调试后,事实证明,当调用scanf两次时,由于某种原因,第一个字符串变为较短的版本,并附加第二个字符串 - 重叠。第二个字符串通常出现在下一行。

有问题的代码(在调试模式下,如果你愿意的话):

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

int main() {
    int p;
    scanf("%d", &p);

    char *s1 = malloc(sizeof(s1));
    char *s2 = malloc(sizeof(s2));
    int len1, len2;
    char *answers[] = { "NO", "YES"};
    int answers_i;
    for(int i = 0; i < p; ++i) {
        scanf("%s", s1);
        scanf("%s", s2);
        printf("%s\n%s\n", s1, s2);
        len1 = strlen(s1);
        len2 = strlen(s2);
        answers_i = 0;
        for(int j = 0; j < len1 && answers_i == 0; ++j) {
            for(int k = 0; k < len2; ++k) {
                if(s1[j] == s2[k]) {
                    // printf("s1[%d]=%c s2[%d]=%c\n", j, s1[j], k, s2[k]);
                    answers_i = 1;
                    break;
                }
            }
        }
        // printf("%s\n", answers[answers_i]);
    }   

    return 0;
}

输入一个失败的测试用例:

10
dapkqnowwvdrknfvcmanjuroumppajrzklucroxvpfmcsclqa
ivtnjtgiogmwhqybjaxlktqbwsdhqrwovoavetymkpcco
hrtybirxncuiailznohfawjwipdtupnxnisbwcplozwrzt
ngdmqotxkpnuhmpfmajthzdtnztrqyugendiublcwp
rmpwlddwttapjzhdldjmuhmgruufltzszprzdcziigc
bbvvkeqkqekqqennyxqxkxnyxnyqnnybnbvnyqqe
annbjookwtqkoivcgbqckqtvgvktobctktgkkjiac
zsspfhmzpurrrlurdsdlrfldzyldfhudfedrszdpmsudh
yuuuydwovzawzamvydaaadkakukpynwfmpnmuaazokxkmjxawo
rqiqbhgscsetgihrrrgsqrlqgcbcbrettlehbeistbiqbisie
ibvmfltfdvlmentbfdemebbnvllfneeefnaamtblt
gukzzrqruyxsrqhyuggkrjujkwjhqhqsrqgkrkqxpszrzk
nakqzfroqouhgunxqvqbxwtibfodsvoilqrpvhtgzoholxd
bqluorjgkkrvmiptnxegxwlhrstiiafbfoxodzyguhdwi
oyvgelovlyevhhedoeolyhdevcvhgceydcdehgvoc
wsqswjnjpiarszzzxpmptrquwbnbzqiqqtzqnbajnpsjfaxr
hvkmgwawagozzabgmdmdvbbaxadawmbazvxohxzv
sfiltrslqepytjpfffqlrpejiueftrnisnnppnlpuficrjys
nvsovybaljmzenkfgayfoxzcjantbdidxflbkhbixgzk
qdphnbrjmznztnphhutkdbwjzmjwugtxggxchzcidngplj

输出

dapkqnowwvdrknfvcmanjuroumppajrzivtnjtgiogmwhqybjaxlktqbwsdhqrwovoavetymkpcco
ivtnjtgiogmwhqybjaxlktqbwsdhqrwovoavetymkpcco
hrtybirxncuiailznohfawjwipdtupnxngdmqotxkpnuhmpfmajthzdtnztrqyugendiublcwp
ngdmqotxkpnuhmpfmajthzdtnztrqyugendiublcwp
rmpwlddwttapjzhdldjmuhmgruufltzsbbvvkeqkqekqqennyxqxkxnyxnyqnnybnbvnyqqe
bbvvkeqkqekqqennyxqxkxnyxnyqnnybnbvnyqqe
annbjookwtqkoivcgbqckqtvgvktobctzsspfhmzpurrrlurdsdlrfldzyldfhudfedrszdpmsudh
zsspfhmzpurrrlurdsdlrfldzyldfhudfedrszdpmsudh
yuuuydwovzawzamvydaaadkakukpynwfrqiqbhgscsetgihrrrgsqrlqgcbcbrettlehbeistbiqbisie
rqiqbhgscsetgihrrrgsqrlqgcbcbrettlehbeistbiqbisie
ibvmfltfdvlmentbfdemebbnvllfneeegukzzrqruyxsrqhyuggkrjujkwjhqhqsrqgkrkqxpszrzk
gukzzrqruyxsrqhyuggkrjujkwjhqhqsrqgkrkqxpszrzk
nakqzfroqouhgunxqvqbxwtibfodsvoibqluorjgkkrvmiptnxegxwlhrstiiafbfoxodzyguhdwi
bqluorjgkkrvmiptnxegxwlhrstiiafbfoxodzyguhdwi
oyvgelovlyevhhedoeolyhdevcvhgceywsqswjnjpiarszzzxpmptrquwbnbzqiqqtzqnbajnpsjfaxr
wsqswjnjpiarszzzxpmptrquwbnbzqiqqtzqnbajnpsjfaxr
hvkmgwawagozzabgmdmdvbbaxadawmbasfiltrslqepytjpfffqlrpejiueftrnisnnppnlpuficrjys
sfiltrslqepytjpfffqlrpejiueftrnisnnppnlpuficrjys
nvsovybaljmzenkfgayfoxzcjantbdidqdphnbrjmznztnphhutkdbwjzmjwugtxggxchzcidngplj
qdphnbrjmznztnphhutkdbwjzmjwugtxggxchzcidngplj

输出应该等于输入,但显然不是这种情况。第一个字符串的上限为32个字符,并且整个第二个字符串都附加到它上面。但第二个字符串本身没有变化。这两个scanf来电之间究竟发生了什么?

我使用gets(oops,已弃用)和getchar,但问题仍然存在。 fgets没用,因为我事先并不知道字符串的大小。我不知道任何其他标准替代品。

注意:如果有人想在HackerRank上试用此代码,请务必选中Test against custom input复选框,复制并粘贴上面的输入,然后点击Run按钮。

1 个答案:

答案 0 :(得分:4)

您的代码有未定义的行为。您的代码中的问题是将内存分配到s1s2。您分配sizeof(s1)个字节,这是指针的大小。一旦读取的数据超过指针大小,就会超过分配的缓冲区,导致未定义的行为。

问题约束要求| a |,| b | &LT; 10 5 ,所以分配如下:

char *s1 = malloc(100000 + 1);
char *s2 = malloc(100000 + 1);

注意为null终止符分配的额外字节。

您需要在功能结束时致电free(s1)free(s2)