分段错误

Segmentation Error

我正在尝试在 Linux 中实现我自己的 shell。我从用户那里获取输入并解析它。但是当我在数组中复制我的标记时它会出现分段错误。我无法解决这个问题。

这是我实现的代码

#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

using namespace std;

int main ()
{
    char * input;
    string insert;
    cout<<"My Shell $";

    getline(cin,insert);
    input= new char [insert.size()+1];
    strcpy(input, insert.c_str());


    char * token;
    char * parsed[100];
    int count;

    token=strtok(input, " ");
    while (token!=NULL)
    {
        strcpy(parsed[count],&(token[count]));
        count++;
        token=strtok(NULL, " ");
    }


}

变量int count未定义,意思是可以是随机值,改成int count = 0;

你没有初始化变量count,它的值是未定义的(可能很大,所以程序从内存中读取会失败)。你应该使用 int count = 0;

并且数组 parsed 中的元素未初始化且未指向分配的内存。您调用 strcpy 的行为也是未定义的。在调用 strcpy 之前添加 parsed[count] = new char[strlen(token) + 1];。完成所有操作后不要忘记使用 delete

最后,我认为你没有正确使用strtok。你为什么使用 &(token[count])?也许您应该将其替换为 token.

只需将您的计数变量初始化为 0

请尝试下面的代码#

#include <iostream>
#include <unistd.h>
#include <string.h>

using namespace std;

int main (void)
{
    char* input = NULL;
    string insert;
    cout<<"My Shell $";

    getline(cin, insert);
    input= new char[insert.size() + 1];
    strcpy(input, insert.c_str());

    char* token = NULL;
    char* parsed[100];

    for (int index = 0; index < 100; index++)
    {
        parsed[index] = NULL;
    }

    int count = 0;

    token = strtok(input, " ");

    while ( token != NULL)
    {
        strcpy(parsed[count], &(token[count]));
        count++;
        token = strtok(NULL, " ");
    }

return 0;
}
#include <string.h>

没有

如果您需要 C 函数,请使用 <cstring>,这会将它们放在 std:: 命名空间中。

但是您不想要 C 函数,您想要C++ <string>。相信我,你相信。

using namespace std;

为了示例的缘故,我将让它通过。在任何生产代码中摆脱这种特殊习惯。

    getline(cin,insert);

很好。您已准备好使用 C++。

    input= new char [insert.size()+1];
    strcpy(input, insert.c_str());

不好。你只是把你的手绑在你的背上。

    char * parsed[100];

一个包含 100 个指向 char 的指针的数组。只是指针,未初始化,指向任何地方。

    int count;

未初始化。

    token=strtok(input, " ");

C。 不寒而栗.....

        strcpy(parsed[count],&(token[count]));

未定义的行为。 count 没有初始化,即使 确实 恰好在 0 到 99 之间,parsed[count] 仍然没有指向有效的内存,所以向它复制一些东西做坏事

此外,您的令牌在 token,而不是 token[count]...

        count++;

未初始化加1就是UB,还是未初始化。 ;-)

}

你忘了delete [] input


让我建议一种不同的、更像 C++ 的方法,它仍然会为您提供指向每个标记的指针数组(如果您坚持这样做):

getline( cin, input );

// turn spaces to null bytes
std::replace( input.begin(), input.end(), ' ', '[=20=]' );

// need an additional one for the finds below to work
input.append( '[=20=]' );

// vector takes away all of that manual memory management
std::vector< char * > parsed;

size_t i = 0;

// skip leading (ex-) spaces
while ( ( i = input.find_first_not_of( '[=20=]', i ) ) != std::string::npos )
{
    // push the pointer to the token on the vector
    parsed.push_back( input.data() + i );

    // skip to end of token
    i = input.find( '[=20=]', i );
}

此时,parsedchar *vectorinput 中的标记(至少,只要 input 本身是仍在范围内)。您可以使用 parsed.size() 检查它的大小,并使用 parsed.data() 作为 "naked" 数组访问它,尽管我相信您会发现 vector 更方便。

如果您不想保留 input,请替换为

std::vector< char * > parsed;

std::vector< std::string > parsed;

parsed.push_back( input.data() + i );

parsed.push_back( std::string( input.data() + i ) );

并且您在 vector.

中有一个 副本 的令牌

请注意,这仍然是相当粗暴的处理,因为即使引号内的空格也会被检测为 "end of token",但至少它是 C++,C 字符串处理的 none。

Please try to use this code. I tried in VS2010 and it is working fine now.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

int main (void)
{
    char* input = NULL;
    string insert;
    cout<<"My Shell $";

   /* getline(cin, insert);*/
    std::getline(cin, insert);
    input= new char[insert.size() + 1];
    strcpy(input, insert.c_str());

    char* token = NULL;
    char* parsed[100] = {0};

    int count = 0;

    token = strtok(input, " ");

    while ( token != NULL)
    {
        parsed[count] = token;
        count++;
        token = strtok(NULL, " ");
    }

    for ( int index = 0; index<count; index++ )
    {
        cout << parsed[index] << std::endl;
    }

    system("pause");
    return 0;
}