修改字符串并返回修改后的字符串的函数

时间:2021-01-02 11:41:50

标签: c concatenation c-strings function-definition

我有一个从宏中获取字符串的函数。它修改字符串,然后返回一个新的修改后的字符串。我的意图是使用这个返回的字符串。但是,它不起作用,因为它不返回修改后的字符串。

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

#define ENCRYPTED_FILE  "hello.txt"

char *decrypt(){
    char str[]=ENCRYPTED_FILE;
    strtok(str,".txt");
    strcat(str,"_decrypted.txt");
    //printf("%s\n",str);
    return str;
};
   
int main()
{        
    printf("%s\n",decrypt());     //output: *** stack smashing detected ***: ./a.out terminated 
    return 0;
}

4 个答案:

答案 0 :(得分:1)

对于初学者来说,该函数返回一个指向本地数组 str 的第一个元素的指针,并具有自动存储持续时间,退出函数后该元素将不存在。

因此函数返回一个无效的指针。

您需要为数组动态分配内存。

还有这个strtok

strtok(str,".txt");

没有意义。该函数不搜索子字符串 ".txt"。它搜索由字符串 ".txt" 指定的字符集的第一个字符。相反,您可以使用函数 strstr

这个代码strcat

 strcat(str,"_decrypted.txt");

调用未定义的行为,因为目标数组没有足够的空间来存储附加的字符串文字。

该函数可以看起来像下面的演示程序中所示。

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

#define ENCRYPTED_FILE  "hello.txt"

char *decrypt( void )
{
    const char *encrypted_file = ENCRYPTED_FILE;
    
    const char *p = strstr( encrypted_file, ".txt" );
    
    if ( p == NULL ) p = encrypted_file + strlen( encrypted_file );
    size_t n = p - encrypted_file;
    
    const char *decrypted_file = "_decrypted.txt";
    
    char *s = malloc( n + strlen( decrypted_file ) + 1 );
    
    memmove( s, encrypted_file, n );
    s[n] = '\0';

    strcat( s + n, decrypted_file );

    return s;
}

int main(void) 
{
    char *s = decrypt();
    
    puts( s );
    
    free( s );
    
    return 0;
}

程序输出为

hello_decrypted.txt

答案 1 :(得分:0)

您正在返回一个指向临时数组的指针,该数组在控制权离开函数后变得悬空。首先,您必须通过 import sys import time import requests while True: main_api = ('https://api.coindesk.com/v1/bpi/currentprice.json') json_data = requests.get(main_api).json() json_updated = json_data['time']['updated'] json_value = json_data['bpi']['USD']['rate'] b ="Bitcoin price: " + json_value + " USD" sys.stdout.write('\r' + b) time.sleep(1) 在堆上分配它,然后确保其分配的大小足以包含原始大小加上额外的“_decrypted”后缀。

答案 2 :(得分:0)

我刚刚注意到您的库符号为 #include "string.h" 而不是 #include <string.h> 可能会解决问题。

答案 3 :(得分:0)

恕我直言,您对 strtok() 函数的使用不当。每次找到点 .tx 时,它都会将字符串拆分为子字符串。由于您已经编写了代码,恐怕这不是您想要的(消除 .txt 后缀?)

阅读 strtok() 的手册页,因为它会准确解释该函数的实际作用。

另一方面,您不能截断 .txt 开头的字符串,然后向其附加更长的字符串。当您声明 str[] 数组时(通过明确不使用长度),编译器保留了尽可能多的字符来保存来自宏的文本,再加上一个字符来保存 \0 分隔符。因此,您的数组只有空间可以容纳 10 个字符("hello.txt" 的 9 个字符,加上字符串 '\0' 结尾的 1 个字符)。当然,那里没有地方容纳 hello_decripted.txt,它需要 19 个字符加上 \0 的一个字符。解决此问题的方法可能是在数组声明中指明您希望编译器使用多少个字符,如下所示:

    char str[100] = ENCRYPTED_FILE;

然后您最多可以扩展 100 个字符(99 个字符加上一个字符串 end char \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" 的文件首先在工作目录中搜索,如果没有找到,则在库固定路径中搜索它们。尝试仅对您的文件或构建目录中的文件使用 ",并仅使用 <> 搜索系统文件。

相关问题