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