您已经走上了正确的道路,应该赞扬您在每次迭代时使用fgets() 从文件中读取完整的行,但是您选择strstr 并不能确保找到您要查找的前缀在行首。
此外,您希望避免对搜索字符串以及要打开的文件进行硬编码。 main() 通过argc 和argv 接受参数,让您在启动时将信息传递到程序中。见:C11 Standard - §5.1.2.2.1 Program startup(p1)。使用参数可以让您将要打开的文件名和要搜索的前缀作为参数传递给程序,从而消除对值进行硬编码的需要。 (这也消除了重新编译代码以读取另一个文件名或搜索另一个字符串的需要)
例如,您可以使用main() 的参数而不是硬编码值来打开任何文件并搜索任何前缀,只需使用类似以下内容:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char buf[MAXC] = "", *str = NULL; /* buffer for line and ptr to search str */
size_t n = 0, len = 0; /* counter and search string length */
double sum = 0; /* sum of matching lines */
FILE *fp = NULL; /* file pointer */
if (argc < 3) { /* validate 2 arguments given - filename, search_string */
fprintf (stderr, "error: insufficient number of arguments\n"
"usage: %s filename search_string\n", argv[0]);
return 1;
}
if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for reading */
perror ("fopen-filename");
return 1;
}
str = argv[2]; /* set pointer to search string */
len = strlen (str); /* get length of search string */
...
此时,在您的程序中,您已经打开了作为第一个参数传递的文件,并通过文件流指针fp 验证了它已打开以供读取。您已将要搜索的前缀作为第二个参数传入,将其分配给指针str,并获得了前缀的长度并存储在len中。
接下来,您希望将文件中的每一行读入buf,但不要尝试将前缀与strstr() 匹配,您可以使用strncmp() 和len 来比较从你的文件。如果找到前缀,则可以使用sscanf 从文件中解析double 值并将其添加到sum 并增加存储在n 中的值的数量,例如
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
if (strncmp (buf, str, len) == 0) { /* if prefix matches */
double tmp; /* temporary double for parse */
/* parse with scanf, discarding prefix with assignment suppression */
if (sscanf (buf, "%*1023[^:]: %lf", &tmp) == 1) {
sum += tmp; /* add value to sum */
n++; /* increment count of values */
}
}
}
(注意:在sscanf()、'*' 的赋值抑制运算符上方允许您读取和丢弃前缀和':',而无需存储第二个字符串中的前缀)
剩下的就是通过检查您的计数n 来检查值是否包含在sum 中,如果是,则输出前缀的平均值。或者,如果 n == 0 在文件中找不到前缀,例如:
if (n) /* if values found, output average */
printf ("prefix '%s' avg: %.4f\n", str, sum / n);
else /* output not found */
printf ("prefix '%s' -- not found in file.\n", str);
}
这基本上就是您所需要的。有了它,您可以从您喜欢的任何文件中读取并搜索任何前缀,只需将文件名和前缀作为前两个参数传递给您的程序。完整的例子是:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char buf[MAXC] = "", *str = NULL; /* buffer for line and ptr to search str */
size_t n = 0, len = 0; /* counter and search string length */
double sum = 0; /* sum of matching lines */
FILE *fp = NULL; /* file pointer */
if (argc < 3) { /* validate 2 arguments given - filename, search_string */
fprintf (stderr, "error: insufficient number of arguments\n"
"usage: %s filename search_string\n", argv[0]);
return 1;
}
if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for reading */
perror ("fopen-filename");
return 1;
}
str = argv[2]; /* set pointer to search string */
len = strlen (str); /* get length of search string */
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
if (strncmp (buf, str, len) == 0) { /* if prefix matches */
double tmp; /* temporary double for parse */
/* parse with scanf, discarding prefix with assignment suppression */
if (sscanf (buf, "%*1023[^:]: %lf", &tmp) == 1) {
sum += tmp; /* add value to sum */
n++; /* increment count of values */
}
}
}
if (n) /* if values found, output average */
printf ("prefix '%s' avg: %.4f\n", str, sum / n);
else /* output not found */
printf ("prefix '%s' -- not found in file.\n", str);
}
使用/输出示例
使用您存储在dat/prefixdouble.txt中的数据文件,您可以搜索文件中的每个前缀并获得平均值,例如
$ ./bin/prefixaverage dat/prefixdouble.txt hhhh
prefix 'hhhh' avg: 0.8874
$ ./bin/prefixaverage dat/prefixdouble.txt xxxx
prefix 'xxxx' avg: 0.9105
$ ./bin/prefixaverage dat/prefixdouble.txt yyyy
prefix 'yyyy' avg: 0.7962
$ ./bin/prefixaverage dat/prefixdouble.txt zzzz
prefix 'zzzz' avg: 0.7897
$ ./bin/prefixaverage dat/prefixdouble.txt foo
prefix 'foo' -- not found in file.
比每次要搜索另一个前缀时都重新编译要容易得多。如果您还有其他问题,请仔细查看并告诉我。