strcat()新行,重复字符串

时间:2008-10-04 02:44:05

标签: c string

我正在编写一个获取系统路径环境变量的函数,将每个路径拆分,然后在其他一些额外字符上进行汇总到每条路径的末尾。

在我使用strcat()函数之前,一切正常(请参阅下面的代码)。

char* prependPath( char* exeName )
{
    char* path = getenv("PATH");  
    char* pathDeepCopy = (char *)malloc(strlen(path) + 1);
    char* token[80];
    int j, i=0; // used to iterate through array

    strcpy(pathDeepCopy, path);

    //parse and split

    token[0] = strtok(pathDeepCopy, ":"); //get pointer to first token found and store in 0
    //place in array
    while(token[i]!= NULL) { //ensure a pointer was found
        i++;
        token[i] = strtok(NULL, ":"); //continue to tokenize the string
    }

    for(j = 0; j <= i-1; j++) {
        strcat(token[j], "/");
        //strcat(token[j], exeName);

        printf("%s\n", token[j]); //print out all of the tokens
    }
}

我的shell输出是这样的(我将“/ which”连接到所有内容上):

...
/usr/local/applic/Maple/bin/which
which/which
/usr/local/applic/opnet/8.1.A.wdmguru/sys/unix/bin/which
which/which
Bus error (core dumped)

我想知道为什么strcat显示新行然后重复which/which。 我也想知道最后的Bus error (core dumped)

使用strcat()之前有没有人见过这个? 如果是这样,任何人都知道如何解决它?

由于

7 个答案:

答案 0 :(得分:6)

strtok()没有给你一个新的字符串 它通过在分割字符为。

的位置插入char'\ 0'来破坏输入字符串

所以你使用strcat(token [j],“/”)会将'/'字符放在'\ 0'所在的位置。
此外,最后一个标记将开始将已分配内存末尾的“哪个”附加到未知内存中。

您可以使用strtok()将字符串拆分为块。但是如果你想在令牌上附加任何东西,你需要制作一个令牌的副本,否则你的追加将溢出到下一个令牌上。

此外,你需要更加小心你的内存分配,你在整个地方泄漏内存: - )

PS。如果必须使用C-Strings。使用strdup()复制字符串。

char* prependPath( char* exeName )
{
    char* path         = getenv("PATH");
    char* pathDeepCopy = strdup(path);
    char* token[80];
    int j, i; // used to iterate through array

    token[0] = strtok(pathDeepCopy, ":");
    for(i = 0;(token[i] != NULL) && (i < 80);++i)
    {
        token[i] = strtok(NULL, ":");
    }

    for(j = 0; j <= i; ++j)
    {
        char*  tmp = (char*)malloc(strlen(token[j]) + 1 + strlen(exeName) + 1);
        strcpy(tmp,token[j]);
        strcat(tmp,"/");
        strcat(tmp,exeName);
        printf("%s\n",tmp); //print out all of the tokens
        free(tmp);
    }
    free(pathDeepCopy);
}

答案 1 :(得分:2)

strtok()标记到位。当您开始向令牌附加字符时,您将覆盖下一个令牌的数据。

另外,一般来说,简单地连接到现有字符串是不安全的,除非您知道字符串所在的缓冲区大小足以容纳结果字符串。这是C程序中的错误的主要原因(包括可怕的缓冲区溢出安全性错误)。

因此,即使strtok()返回与原始字符串无关的全新字符串(它没有),当你连接它们时,你仍然会超出字符串缓冲区。

strcpy()/ strcat()的一些更安全的替代品,你可能想要查看(你可能需要追踪其中一些的实现 - 它们并非都是标准的):

  • strncpy() - 包括目标缓冲区大小以避免溢出。有不总是终止结果字符串的缺点
  • strncat函数()

  • strlcpy() - 类似于strncpy(),但意图更易于使用且更健壮(http://en.wikipedia.org/wiki/Strlcat

  • strlcat提供()

  • strcpy_s() - 这些函数的Microsoft变体

  • strncat_s()

如果你可以使用C ++,你应该努力使用的API: std :: string class 。如果你使用C ++ std :: string类,你几乎不必担心包含字符串的缓冲区 - 该类为你管理所有这些。

答案 2 :(得分:2)

strtok不会复制令牌,而只是在字符串中指向它。因此,当你在令牌的末尾捕捉'/'时,你会在 next 令牌的开头写一个'\ 0',或者超过缓冲区的末尾。

另请注意,即使strtok 已经返回令牌的副本而不是原件(它没有),它也不会为你附加额外空间来附加字符,所以它' d仍然是缓冲区溢出错误。

答案 3 :(得分:1)

如果您使用的是C ++,请考虑boost::tokenizer上讨论的here

如果您遇到C,请考虑使用strtok_r,因为它是可重入且线程安全的。并不是说在这种特殊情况下你需要它,但这是一个很好的习惯。

哦,并使用strdup一步创建重复的字符串。

答案 4 :(得分:1)

好的,首先要小心。你正在失去记忆。 Strtok()返回指向下一个标记的指针,并将其存储在一个字符数组中。 而不是char token [80]它应该是char * token。 使用strtok时要小心。 strtok实际上会破坏名为pathDeepCopy的char数组,因为它会用'\ 0'替换每次出现的“:”。正如Mike F告诉你的那样。 一定要使用calloc的memset初始化pathDeppCopy。 因此,当您编写令牌[i]时,无法知道指向的是什么。 由于令牌中没有数据有效,因此您可能会因为尝试连接而抛出核心转储。另一个没有有效数据(令牌)的字符串。 您正在寻找的Perphaps是指向char的指针数组,其中存储了strtok返回的令牌的所有指针,在这种情况下,令牌将像char * token [];

希望这会有所帮助。

答案 5 :(得分:0)

替换它

strcpy(pathDeepCopy,path);

  //parse and split
    token[0] = strtok(pathDeepCopy, ":");//get pointer to first token found and store in 0
    //place in array
    while(token[i]!= NULL) { //ensure a pointer was found
    i++;
    token[i] = strtok(NULL, ":"); //continue to tokenize the string
    }

// use new array for storing the new tokens 
// pardon my C lang skills. IT's been a "while" since I wrote device drivers in C.
const int I = i;
const int MAX_SIZE = MAX_PATH;
char ** newTokens = new char [MAX_PATH][I];
for (int k = 0; k < i; ++k) {
   sprintf(newTokens[k], "%s%c", token[j], '/');
   printf("%s\n", newtoken[j]); //print out all of the tokens
}

这将取代覆盖内容并阻止核心转储。

答案 6 :(得分:0)

并且不要忘记检查malloc是否返回NULL!