自动将数字附加到 C 中的变量

Automatically appending numbers to variables in C

我们的编程作业要求我们将一个文本文件分成一组名称为 (filename)partx.txt 的较小文件。例如,如果传递给程序的参数是一个名为 stack.txt 的文本文件,那么输出应该是 stackpart1.txt, stackpart2.txt etc,其中每个文件的大小最大为 250 字节。

获得 part_x 东西的最佳方法是什么?

我了解了如何使用带有 ## 的宏来实现这一点。这种方法有什么缺点,有什么更好的方法吗? 以这种方式生成变量名是一种好习惯吗?

您可以:

  • 按照建议使用 MACRO(编译时)。这涉及在实现代码时要提供的有关文件大小(和子文件数量)的一些知识。
  • 在循环中使用 snprintf() 生成文件名。(运行时)。这可以根据一些算法动态使用,用于测量文件大小。

也就是说,最好的方法:使用 snprintf()

不要将变量名与其内容混淆;宏和变量名与您的分配无关。 ## 用于在 编译时 连接要在代码中使用的字符串(典型用法是在宏中参数化地构建标识符或一般代码),这是一个相对罕见且非常专业的任务。

相反,您想要做的是在运行时根据模式生成 字符串 (=> 您将拥有与填充相同的字符串变量每次迭代都有不同的东西);正确的功能是 snprintf.

非常简单,我会说:你打开一个文件 (fopen returns a FILE *) 然后你可以使用 [=14= 循环读取它] 指定每次迭代读取的最大字节数。鉴于您无论如何都在使用循环,您可以增加一个简单的 int 来跟踪块文件名,使用 snprintf 创建名称,将 fread 读取的字符写入每个文件,然后继续,直到完成。

Some details on fread that might be useful to you

一个基本示例(仍然需要一些工作):

int main( void )
{
   int chunk_count = 0, chunk_size = 256;
   char buffer[256]
   FILE *src_fp,
        *target_fp;
   char chunk_name[50];

   while (chunk_size == fread(buffer, chunk_size, 1, src_fp))
   {//read chunk
       ++chunk_count;//increase chunk count
       snprintf(chunk_name, 50, "chunk_part%d.txt", chunk_count);
       target_fp = fopen(chunk_name, "w");
       //write to chunk file
       fwrite(buffer, chunk_size, 1, target_fp);
       fclose(target_fp);//close chunk file
   }
   //don't forget to write the last chunk, if it's not 0 in length
   if (chunk_size)
   {
       ++chunk_count;//increase chunk count
       snprintf(chunk_name, 50, "chunk_part%d.txt", chunk_count);
       target_fp = fopen(chunk_name, "w");
       //write to chunk file
       fwrite(buffer, strlen(buffer) + 1, 1, target_fp);
       fclose(target_fp);//close chunk file
   }
   fclose(src_fp);
   printf("Written %d files, each of max 256 bytes\n", chunk_count);
   return 0 ;
}

请注意,按原样使用此代码并不完全安全。您需要检查 fopen 的 return 值(它 可以 ,并且在某些时候会 return NULL) .基于 fread 的循环简单地假设,如果它的 return 值小于块大小,我们已经到达源文件的末尾,但情况并非总是如此。您仍然必须自己处理 NULL 指针和 ferror 东西。无论哪种方式,要研究的函数是:

  • fread
  • fopen
  • fwrite
  • fclose
  • ferror
  • snprintf

应该可以了。


更新,自娱自乐

您可能想要填充块文件名的数字 (chunk_part0001.txt)。要做到这一点,您可以尝试预测源文件有多大,将其除以 256 以计算出您实际最终将得到多少块,并使用该数量的填充零。如何获取文件大小is explained here,但这是我前段时间的一些代码:

long file_size = 0,
     factor = 10;
int padding_cnt = 1;//at least 1, ensures correct padding
fseek(src_fp, 0, SEEK_END);//go to end of file
file_size = ftell(src_fp);
file_size /= 256;//divided by chunk size
rewind(src_fp);//return to beginning of file
while(10 <= (file_size/factor))
{
    factor *= 10;
    ++padding_cnt;
}
//padded chunk file names:
snprintf(chunk_name, sizeof chunk_name, "chunk_part%0*d.txt", padding_cnt, chunk_count);

如果你愿意,我可以解释每一个陈述,但它的要点是:

  • fseek + ftell 得到文件的大小(以字节为单位),除以块大小 (256) 得到你将创建的块总数(+1余数,这就是 padding_cnt 被初始化为 1)
  • 的原因
  • while循环将总计数除以10^n,因子每乘以10,填充计数增加
  • 传递给 snprintf 的格式更改为 %0*d 这意味着:_"打印一个 int,用 n 次出现的 0 填充(即固定宽度)。如果你最终得到 123块,第一个块文件将被称为 chunk_part001.txt,第十个文件将是 chunk_part010.txt,一直到 chunk_part100.txt
  • 参考链接问题,接受的答案使用sys/stat.h来获取文件大小,这更可靠(尽管它可能会带来一些小的可移植性问题)Check the stat wiki for alternatives

为什么?因为它很有趣,而且它使输出文件更容易按名称排序。它还使您能够预测包含目标文件名的字符数组应该有多大,因此如果您必须使用 malloc 分配该内存,您就会确切地知道需要多少内存,并且不需要必须分配 100 个字符(无论哪种方式都应该足够),并希望你不要 运行 out of space.
最后:你知道的越多,IMO 就越好,所以我想我会给你一些你可能想要检查的链接和参考。