【问题标题】:C: creating new file extensions based on a filenameC:根据文件名创建新的文件扩展名
【发布时间】:2012-08-06 21:17:08
【问题描述】:

我想根据具有不同扩展名的基本文件名来命名输出文件。在 C 伪代码中:

a_file = fopen(filename + ".dt1","wt");
b_file = fopen(filename + ".dt2","wt");
c_file = fopen(filename + ".dt3","wt");

我尝试使用strncat 跟踪this 示例,但我的程序一直附加到filename

f1=fopen(strcat(filename,".dt1"),"wt");
f2=fopen(strcat(filename,".dt2"),"wt");
f3=fopen(strcat(filename,".dt3"),"wt");

这个输出:

filename.dt1
filename.dt1.dt2
filename.dt1.dt2.dt3

我需要最终结果看起来像:

filename.dt1
filename.dt2
filename.dt3

【问题讨论】:

  • 你不能每次都使用不同的变量,因此将一个变量作为 fileName 并使用存储在 fileName 中的相同字符串,因为根据 strcat 的帮助,它改变了其他类型的内容目标字符串
  • 你不能每次都增加最后一个字符吗?

标签: c string strcat


【解决方案1】:

那是因为strcat 直接写入第一个字符串的缓冲区。

最简单的方法可能是使用snprintf 将两个字符串连接在一起:

snprintf(filename_a, n+4, "%s.dt1", filename);
snprintf(filename_b, n+4, "%s.dt2", filename);
snprintf(filename_c, n+4, "%s.dt3", filename);

这里,filename 的长度为n(包括尾随的\0),而filename_afilename_bfilename_c 是长度至少为n+4 的缓冲区。

(你也可以使用sprintf,但小心一点总是好的。)

【讨论】:

  • +1:更好,如果他的编译器支持C99,就是使用snprintf
  • 我使用的是 Visual Studio 2010,它不知道函数 snprintf。我刚刚使用了 sprintf。
【解决方案2】:

考虑到strcat 将扩展名附加到给定字符串,您的代码按预期工作。您只使用了一个字符串,因此扩展名相互叠加。

这是执行此操作的一种方法,修改您发布的代码,该代码使用单个字符串作为filename

size_t len = strlen(filename);
f1 = fopen(strcat(filename, ".dt1"), "wt");
filename[len] = '\0';
f2 = fopen(strcat(filename, ".dt2"), "wt");
filename[len] = '\0';
f3 = fopen(strcat(filename, ".dt3"), "wt");

将此索引设置为 \0 可以有效地将 filename 截断回调用之间的原始字符串。

请注意,filename 必须足够大以包含附加的扩展名 - 4 个额外字符的空间 - 这样做会丢失中间文件打开每个文件后的名称。

或者,如果您的扩展名仅在最后一个字符上有所不同:

size_t len = 0;
f1 = fopen(strcat(filename, ".dt1"), "wt");
len = strlen(filename);
filename[len - 1] = '2';
f2 = fopen(filename), "wt");
filename[len - 1] = '3';
f3 = fopen(filename, "wt");

适用与上述相同的注意事项。

【讨论】:

  • 注意他为什么会遇到问题可能会有所帮助。他将它们叠加在一起,因为他重用了相同的字符串,而不是创建源字符串。
  • 我们对如何为 filename 分配存储空间一无所知 - 缓冲区溢出的可能性很大,而且会爆炸。
【解决方案3】:

使用标准 C 库有点痛苦,但我会这样做。

    char *fn = malloc(strlen(filename+5)); // Allocate a string with enough space
                                           // for the extensions.

    sprintf(fn, "%s.dt1", filename);       // Copy the name with extensions into fn.
    a_file = fopen(fn,"wt");               //
    sprintf(fn, "%s.dt2", filename);       //
    b_file = fopen(fn,"wt");               //
    sprintf(fn, "%s.dt3", filename);       //
    c_file = fopen(fn,"wt");               //

    free(fn); // Free the memory gained from malloc.

【讨论】:

  • 谢谢。您的代码运行良好,尽管没有解释。 :( 您的代码以及上面 pb2q 和 Sebastian Paaske Tørholm 的解释帮助我理解了 strcat 的工作原理。
【解决方案4】:

我会说你的输出非常合理:

char * strcat ( char * destination, const char * source );

将源字符串的副本附加到目标字符串。目标中的终止空字符被源的第一个字符覆盖,并在目标中两者连接形成的新字符串的末尾附加一个新的空字符。

因此,filename 指向的字符数组既是从 strcat 返回的,又是通过连接结果修改的。

非常简单的解决方法是在修改之前记住文件名长度,然后:

filename[filename_length_before_modification] = '\0';

这将有效地减少附加的扩展名并让您回到起点

【讨论】:

  • 如何找出“文件名”(数组)的长度?我假设做类似 int len = sizeof(filename)?然后 filename[int] = '\0'?
  • 最好使用 strlen(filename)。 sizeof(filename) 最好可以返回数组的总大小,然后您将超出其边界。根据您声明它的方式,它也可能只返回 sizeof(char*)
【解决方案5】:

一种更有效的方式。它每次只复制扩展名。如果我们假设只有最后一个字符发生变化(参见 pb2q 的second solution),它可以变得更加高效。

(未经测试,可能差一分)

size_t len = strlen(filename);
char *buf = malloc(len+4); // Allocate a string with enough space for the
                           // extensions.
strcpy(buf, filename);
char *ext = buf+len // Get a pointer to where the extension starts.

strcpy(ext, ".dt1");             // Copy the name with extensions into fn.
FILE *a_file = fopen(buf, "wt"); //
strcpy(ext, ".dt2");             // 
FILE *b_file = fopen(buf, "wt"); //
strcpy(ext, ".dt3");             // 
FILE *c_file = fopen(buf, "wt"); //

free(buf); // Free the memory gained from malloc.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 2016-12-06
    • 1970-01-01
    • 2011-05-17
    • 2021-07-13
    相关资源
    最近更新 更多