读一个每行两个字的文件,并用C高效地保存这些字
我有一个文本文件,每行有一对单词,我用它来阅读它们:读一个每行两个字的文件,并用C高效地保存这些字,c,C,我有一个文本文件,每行有一对单词,我用它来阅读它们: for (i=0, j=0; (c=fgetc(fp))!=EOF; i++){ if (c == ' '){ pares[j].par1[i] = '\0'; for (i=0; (c=fgetc(fp))!= '\n'; i++){ pares[j].par2[i] = c; } j++; i= -1;
for (i=0, j=0; (c=fgetc(fp))!=EOF; i++){
if (c == ' '){
pares[j].par1[i] = '\0';
for (i=0; (c=fgetc(fp))!= '\n'; i++){
pares[j].par2[i] = c;
}
j++;
i= -1;
}
else{
pares[j].par1[i]=c;
}
}
n_pares = j;
fclose(fp);
“pares”是一个结构,它有行的第一个单词(par1)和第二个单词(par2),我知道我不需要这样做。但我不知道这是否是最有效的方法。因为在python中,我只使用函数split(),而不需要执行for循环。有谁能告诉我有没有更有效的方法吗?与逐字读取相比,通常更有效的方法是分配一个大的行缓冲区,将行读入该缓冲区,并将其处理为大小更合适的块
char line[1024];
while(fgets(line, 1024, fp) != NULL) {
...now process line...
}
在C语言中拆分一行比在高级语言中要困难一些。标准函数是(字符串标记),使用起来有点滑稽
const char sep[] = " \t\n";
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
printf("%s ", token);
}
printf("\n");
发生的事情是,strtok在查看字符串时会记住它的位置,但它一次只能对一个字符串执行此操作。在字符串中传递它会将其重置回起始位置。因此,strtok(line,sep)
在line
上启动进程,strtok(NULL,sep)
在line
上获取下一个令牌,直到没有剩余令牌为止
此全局状态由对strtok
的所有调用共享,因此在使用strtok
时调用另一个函数甚至不安全,该函数也可能调用strtok
并重置状态
非标准更安全,它使用一个变量来记住它在哪里。有更好的界面,但它也是非标准的
这些都是通过修改正在迭代的字符串来实现的<代码>标记只是指向行
的指针。例如,如果我们有这样的东西:
// Let's say line is pointing at memory location 1000
// 'U' is at 1000, 'p' is at 1001, ' ' is at 1002, etc...
line = 1000
|
v
"Up down\n\0"
第一次调用char*token=strtok(line,sep)代码>会导致这种情况
line = 1000
|
v
"Up\0down\n\0"
^
|
token = 1000
标记
指向字符串的开头,但请注意,空格已替换为空字节。这使您可以使用令牌
作为字符串“Up”
,而无需分配新内存。请注意,字符串已修改
第二个token=strtok(NULL,sep)
导致token
移动
line = 1000
|
v
"Up\0down\0\0"
^
|
token = 1003
结尾的换行符已替换为空字节。现在token
包含字符串“down”
,但它只是指向与行共享的内存。如果您打印行
,您将得到“向上”
在最后一个token=strtok(NULL,sep)
上,token
将被设置为NULL,因为不再有非分隔符字符<代码>行
保持修改状态
line = 1000
|
v
"Up\0down\0\0"
token = NULL
关键是,您不能存储标记
,因为它指向行
,并且行
将更改循环的下一次迭代。您必须复制标记
所指向的字符串,例如。这非常节省内存,避免了不必要的内存分配和复制,但如果您来自更高级别的语言,则可能会有点难以理解。通常,一次分配一个大的行缓冲区,将行读入该缓冲区,而不是逐字符读取,效率更高,并将其加工成尺寸更合适的零件
char line[1024];
while(fgets(line, 1024, fp) != NULL) {
...now process line...
}
在C语言中拆分一行比在高级语言中要困难一些。标准函数是(字符串标记),使用起来有点滑稽
const char sep[] = " \t\n";
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
printf("%s ", token);
}
printf("\n");
发生的事情是,strtok在查看字符串时会记住它的位置,但它一次只能对一个字符串执行此操作。在字符串中传递它会将其重置回起始位置。因此,strtok(line,sep)
在line
上启动进程,strtok(NULL,sep)
在line
上获取下一个令牌,直到没有剩余令牌为止
此全局状态由对strtok
的所有调用共享,因此在使用strtok
时调用另一个函数甚至不安全,该函数也可能调用strtok
并重置状态
非标准更安全,它使用一个变量来记住它在哪里。有更好的界面,但它也是非标准的
这些都是通过修改正在迭代的字符串来实现的<代码>标记
只是指向行
的指针。例如,如果我们有这样的东西:
// Let's say line is pointing at memory location 1000
// 'U' is at 1000, 'p' is at 1001, ' ' is at 1002, etc...
line = 1000
|
v
"Up down\n\0"
第一次调用char*token=strtok(line,sep)代码>会导致这种情况
line = 1000
|
v
"Up\0down\n\0"
^
|
token = 1000
标记
指向字符串的开头,但请注意,空格已替换为空字节。这使您可以使用令牌
作为字符串“Up”
,而无需分配新内存。请注意,字符串已修改
第二个token=strtok(NULL,sep)
导致token
移动
line = 1000
|
v
"Up\0down\0\0"
^
|
token = 1003
结尾的换行符已替换为空字节。现在token
包含字符串“down”
,但它只是指向与行共享的内存。如果您打印行
,您将得到“向上”
在最后一个token=strtok(NULL,sep)
上,token
将被设置为NULL,因为不再有非分隔符字符<代码>行
保持修改状态
line = 1000
|
v
"Up\0down\0\0"
token = NULL
关键是,您不能存储标记
,因为它指向行
,并且行
将更改循环的下一次迭代。您必须复制标记
所指向的字符串,例如。这非常节省内存,避免了不必要的内存分配和复制,但如果您来自更高级别的语言,则可能会有点难以理解。代码的最后两行在此不重要。请不要尝试描述结构:发布。如果代码可以工作,但您希望它更好,也许可以在CodeReview上发布?附言:我会用fgets
阅读,用strtok
“最有效的方法”进行拆分