恕我直言,您对strtok() 功能的使用不当。每次找到点.、t 或x 时,它都会将字符串拆分为子字符串。正如您编写的代码,恐怕这不是您想要的(消除.txt 后缀?)
阅读strtok() 的手册页,它会准确解释这个函数的实际作用。
另一方面,您不能截断.txt 开头的字符串,然后将更长的字符串附加到它上面。当您声明 str[] 数组(通过明确不使用长度)时,编译器保留了尽可能多的字符来保存来自宏的文本,再加上一个来保存 \0 分隔符。所以你的数组只有空间来容纳 10 个字符("hello.txt" 的 9 个字符,加上一个用于字符串结尾的'\0')。当然,没有地方可以容纳hello_decripted.txt,这需要19 个字符加上\0 的1 个字符。解决此问题的方法可能是在数组声明中指明您希望编译器使用多少个字符,如下所示:
char str[100] = ENCRYPTED_FILE;
然后您最多可以扩展 100 个字符(99 个字符加上字符串结尾字符 \0 的持有者)。
如果您找到要搜索的字符串 (.txt) 并将 \0 放在它的第一个位置,您将截断原始字符串,您将能够执行您真正想要的操作,即是:
#include <stdio.h>
#include <stdlib.h>
#include "string.h" /* is this what you actually mean and not <string.h>? */
#define ENCRYPTED_FILE "hello.txt"
char *decrypt(){
char str[100]=ENCRYPTED_FILE;
char *p = strstr(str,".txt");
if (p != NULL) { /* the string actually has a .txt suffix */
*p = '\0'; /* string truncated */
}
strcat(str,"_decrypted.txt"); /* add new suffix */
//printf("%s\n",str);
/* you cannot return str as str is a local variable,
* and it will cease to exist as soon as we leave this
* function body, better return a new dynamically
* allocated string (that need to be freed with free(3)
*/
return strdup(str);
};
int main()
{
/* the stack smashing probably is due to returning the
* address of a local variable, that ceased to exist.
*/
char *name = decrypt();
printf("%s\n", name);
free(name); /* return the memory allocated in decrypt() */
return 0;
}
这将解决尊重您意图的问题。但你在另一点上错了:
如果字符串.txt 出现在原始名称的末尾之前怎么办?在我看来,您要搜索的是.txt 后缀(以前称为扩展名) 是什么阻碍了您的文件被命名为blahblah.txt01.txt 之类的名称? --其中出现了两次子字符串.txt--) 这不是搜索.txt 后缀的正确算法。正确的方法是搜索.txt 是否在字符串的末尾,为此,使用的算法不同(而且效率更高):
char *decrypt(){
char str[100]=ENCRYPTED_FILE;
char *suff = ".txt";
/* go to the point that is strlen(str) further than
* the beginning of the string minus the string
* of the suffix */
char *p = str + strlen(str) - strlen(suff);
if (strcmp(p, suff) == 0) { /* the string actually has a .txt suffix */
*p = '\0'; /* string truncated */
}
/* from this point on, everything goes the same */
strcat(str,"_decrypted.txt"); /* add new suffix */
//printf("%s\n",str);
return strdup(str);
};
在这种情况下,您只需要进行一次字符串比较(在 strstr() 的正文中进行多次以搜索完整匹配),您就会知道它是否失败或没有快速有效地进行。
注意
关于代码中#include "string.h" 行的最后一点说明:如果您有一个名为相同的本地文件(在本地目录中),则可以包含一个带双引号的文件而不是一对<> 字符作为一些库文件,因为这将使它在系统库之一之前被找到。但是如果你包含标准库的包含文件是一个坏习惯,因为如果你以后决定创建一个包含文件(在其他模块或程序中)并创建一个本地string.h文件,这个程序会突然开始编译错误你不会猜到为什么。小心#include 名称和调用它们的两种方式。命名为<file.h> 的文件通常是标准库包含文件,在系统的固定位置进行搜索。命名为"file.h" 的文件首先在工作目录中搜索,如果没有找到,则在库固定路径中搜索。尝试仅将" 用于您的文件或构建目录中的文件,并仅使用< 和> 搜索系统文件。