strcmp分段错误

时间:2011-01-05 17:07:09

标签: c++ c

这是一个来自spoj的问题。与算法无关,但只是c

示例输入

2

a aa bb cc def ghi

a a a a a bb bb bb bb c c

示例输出

3

5

它计算相同单词的最长序列 http://www.spoj.pl/problems/WORDCNT/ 这个词不到20个字符 但是当我运行它时,它会给出分段错误。我使用eclipse调试它。这是它崩溃的地方

if (strcmp(previous, current) == 0)
                currentLength++;

带有以下消息

没有可用于“strcmp()0x2d0100”的源代码“ 有什么问题?

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
int main(int argc, const char *argv[])
{
    int t;
    cin >> t;
    while (t--) {
        char line[20000], previous[21], current[21], *p;
        int currentLength = 1, maxLength = 1;
        if (cin.peek() == '\n') cin.get();
        cin.getline(line, 20000);

        p = strtok(line, " '\t''\r'");
            strcpy(previous, p);

        while (p != NULL) {
            p = strtok(NULL, " '\t''\r'");
            strcpy(current, p);

            if (strcmp(previous, current) == 0)
                currentLength++;
            else
                currentLength = 1;
            if (currentLength > maxLength)
                maxLength = currentLength;
        }
        cout << maxLength << endl;
    }
    return 0;
}

8 个答案:

答案 0 :(得分:9)

问题可能在这里:

    while (p != NULL) {
        p = strtok(NULL, " '\t''\r'");
        strcpy(current, p);

输入循环时p可能不为NULL 在使用strcpy时它可能为NULL。

更正确的循环形式是:

    while ((p != NULL) && ((p = strtok(NULL, " \t\r")) != NULL))
    {
        strcpy(current, p);

请注意。使用C ++对流进行标记更加容易。

std::string  token;
std::cin >> token;  // Reads 1 white space seoporated word

如果你想标记一行

// Step 1: read a single line in a safe way.
std::string line;
std::getline(std::cin, line);

// Turn that line into a stream.
std::stringstream  linestream(line);

// Get 1 word at a time from the stream.
std::string token;
while(linestream >> token)
{
    // Do STUFF
}

答案 1 :(得分:2)

忘了在strtok上检查NULL,完成后它将返回NULL,你不能在strcpy,strcmp等上使用那个NULL。

请注意,您在strtok之后立即执行strcpy,在使用p作为源之前,应检查null。

答案 2 :(得分:2)

strtok手册页说:

 Each call to strtok() returns a pointer to a null-terminated string containing the next 
token. This string does not include the delimiting character. If no more tokens are found, 
strtok() returns NULL. 

在你的代码中,

while (p != NULL) {
            p = strtok(NULL, " '\t''\r'");
            strcpy(current, p);

一旦整个字符串被解析,你就不会检查NULL(对于p)。之后,您正试图在current中复制p(现在为NULL),从而导致崩溃。

答案 3 :(得分:1)

你会发现previouscurrent中的一个在该点没有指向以空字符结尾的字符串,因此strcmp不知道何时停止。

使用适当的C ++字符串和字符串函数,而不是混合使用C和C ++。 Boost库可以提供比strtok更安全的tokeniser。

答案 4 :(得分:1)

您可能会将当前和之前的内容缩小。你应该真的使用std :: string来做这件事 - 这就是它的用途。

答案 5 :(得分:0)

在将字符串长度复制到大小为21的缓冲区之前,你没有做任何事情来检查你的字符串长度。我打赌你以某种方式覆盖了缓冲区的末尾。

答案 6 :(得分:0)

如果你坚持使用C字符串,我建议使用strncmp而不是strcmp。这样,如果您最终得到一个非空终止字符串(我怀疑是这种情况),您可以将比较限制为字符串的最大长度(在本例中为21)。

答案 7 :(得分:0)

试试这个...

#include <cstdio>
#include <cstring>
#define T(x) strtok(x, " \n\r\t")
char line[44444];
int main( )
{
        int t; scanf("%d\n", &t);
        while(t--)
    {
            fgets(line, 44444, stdin);
            int cnt = 1, len, maxcnt = 0, plen = -1;
            for(char *p = T(line); p != NULL; p = T(NULL))
        {
                len = strlen(p);
                if(len == plen) ++cnt;
                    else cnt = 1;

            if(cnt > maxcnt) 
                 maxcnt = cnt;
                    plen = len;
            }
        printf("%d\n", maxcnt);
        }
        return 0;
    }