对于行,fgets 足以逐行读取
size_t rows = 0;
char buffer[256] = {0};
FILE* f = fopen("test.txt", "r");
if (!f)
{
fprintf(stderr, "Could not open file\n");
return 1;
}
while (fgets(buffer, sizeof buffer, f) != NULL)
{
if (strchr(buffer, '\n') != NULL)
{
// Increment row counter if a newline is present in the string
rows++;
}
else if (feof(f))
{
// Increment even if there's no newline but EOF has been reached
rows++;
}
}
fclose(f);
printf("rows: %d\n", rows);
return 0;
fgets 最多会读入sizeof(buffer) - 1 个字符或直到遇到的第一个换行符,以先到者为准。
这意味着某些行大于缓冲区大小(在本例中为 256)的读取,将不会读取整行。所以我们需要在递增之前检查字符串中是否真的存在换行符strchr。
对于列,假设所有行的列数相同,您可以简单地计算包含整行的buffer 中的空格数(不连续)
size_t columns = 0;
char buffer[256] = {0};
FILE* f = fopen("test.txt", "r");
if (!f)
{
fprintf(stderr, "Could not open file\n");
return 1;
}
// Read the first line in full, keep trying until a newline is encountered
while (strchr(buffer, '\n') == NULL && fgets(buffer, sizeof buffer, f) != NULL)
{
// Keep track of whether or not actual column data has been encountered
bool data_encountered = false;
for (size_t i = 0; i < strlen(buffer) - 1; i++)
{
if (buffer[i] != ' ')
{
// NOTE: This assumes any non space character is valid column data
data_encountered = true;
}
else if (data_encountered)
{
// Encountered space, if column data had been encountered prior - increment count
columns++;
// Reset data_encountered
data_encountered = false;
}
}
}
// Increment columns one last time if line ended with a non space character
size_t bufferlen = strlen(buffer);
if (buffer[bufferlen - 1] == '\n')
{
// Buffer ended in a newline, check the character just before it
// Increment column count if the last character (excluding newline is a valid column data)
columns += (buffer[bufferlen - 2] != ' ');
}
else
{
// Increment column count if the last character (excluding newline is a valid column data)
columns += (buffer[bufferlen - 1] != ' ');
}
fclose(f);
printf("columns: %d\n", columns);
return 0;
循环一直调用fgets,直到缓冲区中出现换行符,即已读取一行。在循环内部,对于每个缓冲区,将空格数(非连续)添加到计数器中,表示列。
如果你事先知道列数的上限,甚至每行字符数的上限 -您将不需要所有这些保护措施。但在您无法猜测的情况下,这将是可靠的。
现在,你如何组合它们?我建议将它们放在单独的函数中,一个用于计算行数,另一个用于计算列数。不用担心性能,如果编译器看到这两个函数在彼此附近被调用,它会处理这个问题。
但是如果你坚持在同一个函数中完成所有这些,这里有一个有效的实现-
int columns = 0, rows = 0;
char buffer[256] = { 0 };
FILE* f = fopen("test.txt", "r");
if (!f)
{
fprintf(stderr, "Could not open file\n");
return 1;
}
// Extract the first line and count the columns
while (strchr(buffer, '\n') == NULL && fgets(buffer, sizeof buffer, f) != NULL)
{
// Keep track of whether or not actual column data has been encountered
bool data_encountered = false;
for (size_t i = 0; i < strlen(buffer) - 1; i++)
{
if (buffer[i] != ' ')
{
// NOTE: This assumes any non space character is valid column data
data_encountered = true;
}
else if (data_encountered)
{
// Encountered space, if column data had been encountered prior - increment count
columns++;
// Reset data_encountered
data_encountered = false;
}
}
}
// Increment columns one last time if line ended with a non space character
size_t bufferlen = strlen(buffer);
if (buffer[bufferlen - 1] == '\n')
{
// Buffer ended in a newline, check the character just before it
// Increment column count if the last character (excluding newline is a valid column data)
columns += (buffer[bufferlen - 2] != ' ');
}
else
{
// Increment column count if the last character (excluding newline is a valid column data)
columns += (buffer[bufferlen - 1] != ' ');
}
// Increment rows by one, since one line has been read already
rows++;
// Reset all cells in the buffer to 0
memset(buffer, 0, sizeof buffer);
// Count the rest of the lines
while (fgets(buffer, sizeof buffer, f) != NULL)
{
if (strchr(buffer, '\n'))
{
rows++;
}
else if (feof(f))
{
rows++;
}
}
fclose(f);
printf("rows: %d\n", rows);
printf("columns: %d\n", columns);
注意:要包含在代码中的标头-
#include <stdio.h>
#include <string.h>
#include <stdbool.h>