c - 在复制 wc 命令的 C 程序中使用两个缓冲区
问题描述
我有以下代码模拟来自 linux 的 wc 命令。我需要使用尺寸为 4096 的缓冲区,但由于某种原因,当我执行此代码时,我得到以下结果:
0 0 0 wcfile
即使文件不为空,我也会得到 0 行、单词和字节。我正在使用的代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define LUNG_BUF 4096
int main(int argc, char** argv)
{
int bytes = 0;
int words = 0;
int newLine = 0;
char buffer[LUNG_BUF];
enum states { WHITESPACE, WORD };
int state = WHITESPACE;
if ( argc !=2 )
{
printf( "Nu ati introdu snumele fisierului\n%s", argv[0]);
}
else{
FILE *file = fopen( argv[1], "r");
if(file == 0){
printf("can not find :%s\n",argv[1]);
}
else{
char *thefile = argv[1];
while (read(fileno(file),buffer,LUNG_BUF) ==1 )
{
bytes++;
if ( buffer[0]== ' ' || buffer[0] == '\t' )
{
state = WHITESPACE;
}
else if (buffer[0]=='\n')
{
newLine++;
state = WHITESPACE;
}
else
{
if ( state == WHITESPACE )
{
words++;
}
state = WORD;
}
}
printf("%d %d %d %s\n",newLine,words,bytes,thefile);
}
}
}```
解决方案
read 尝试将最多 LUNG_BUF 字节读入缓冲区并返回实际读取的字节数(或在文件结束的情况下为零或 -1 表示错误)。
这意味着检查== 1
将在大多数情况下失败。
如果您想解释数据,那么读取比最大缓冲区大小少一个字节也是有意义的,以便能够在缓冲区末尾放置一个终止 NUL 字节。
然后,您可以评估此数据,例如,通过使用在每次循环传递时设置为缓冲区开头的指针。
所以你的代码看起来像这样:
size_t n;
while ((n = read(fileno(file), buffer, LUNG_BUF - 1)) > 0) {
buffer[n] = '\0';
char *ptr = buffer;
while (*ptr) {
bytes++;
if (*ptr == ' ' || *ptr == '\t') {
state = WHITESPACE;
} else if (*ptr == '\n') {
newLine++;
state = WHITESPACE;
} else {
if (state == WHITESPACE) {
words++;
}
state = WORD;
}
ptr++;
}
}
如果该行实际上更长,则另一种选择是使用提供一行或最多 4095 个字节的数据的 fgets(因为 fgets 附加了至少一个终止 NUL 字节)。
因此,您的循环稍作修改将如下所示:
while (fgets(buffer, sizeof(buffer), file)) {
char *ptr = buffer;
while (*ptr) {
...
推荐阅读
- c# - 使用组合框中的包含无法正确过滤列表
- vba - MS Word - 查找带有换行文本的表格行
- abap - 在 SAP GUI 中显示自定义图标
- angular - 将 Angular 的依赖项移动到 devDependencies
- php - 如何在 Laravel 控制器中使用“for 循环”而不是“foreach 循环”?
- angular - BehaviorSubject 为每个订阅发出相同的值
- amazon-web-services - 如果我在 Cloudfront 上启用了 SSL,AWS ALB 是否需要 SSL?
- azure - QnA Maker 在 MS Teams 中部署时不显示按钮
- javascript - 如何在窗口关闭 MSCRM 上将值从 HTML webresource 传递到 javascript
- c++ - 如何在 C++ 中使用 unix 时间格式化 time_t 中的时间/日期字符串