我需要读取一行高达128字节的16字节的数据块,建议我使用fgets,但我有2个主要问题。
首先,当检测到n时,它不会停止读取。我需要它与Linux终端一起工作,如果使用例如
echo"ls-l\nls-l\nls-l"|/分枝杆菌
作为stdout,我希望看到的是不同行中的3个命令,但我看到的是"ls-l\nls-l\nls"作为第一行-l〃;作为第二行。我需要我的代码来处理这个精确的输入(还有很多其他的,但这只是一个例子(。因此,我需要代码识别并停止读取,直到我告诉程序继续读取。
这就是我现在所做的测试:
#include <stdio.h>
#include <stdlib.h>
#define BUF_SIZE 16
int main(){
char *buf = malloc(sizeof(char) * BUF_SIZE);
while((fgets(buf, BUF_SIZE + 1, stdin)) != NULL){
fprintf(stdout, "%sn", buf);
}
return 0;
}
此外,一旦我可以毫无问题地读取该行直到换行,我还需要将读取的所有部分组合到一个也是char *
类型的变量中。
我需要以16字节的块读取一行最多128字节,建议我使用fgets,但我有2个主要问题。
首先,当检测到时,它不会停止读取
这只是不正确的。我[和其他]在前面的问题中已经提到了这一点。
再次,当fgets
看到n
时,它将停止。
上面使用fgets
的代码具有UB(未定义的行为(。它分配一个长度为16的缓冲区。但是,它通过16 + 1
到fgets
。这意味着fgets
可以读取通过导致UB的缓冲区的末尾(即错误(。
两种情况下都需要相同的长度。而且,如果你想要一个16字节的数据块,你想要传递的长度可能是17。
同样参考前面的问题,我有一个fgets
解决方案:如何以16字节为一组从stdin读取到新行?c
您似乎想要使用一种解决方案,该解决方案在read
上以16字节块的形式循环,并在n
上停止。换句话说,您的老师希望您实现自己的fgets
函数。
问题的关键在于,您需要一个能够跨调用记住状态的struct
。它必须有一个";保持";read
将数据放入的缓冲区,保持缓冲区的偏移量和长度。当检测到换行符时,必须将数据复制出来。长度会被调整,并且剩余的字符[由read
读取,但不是传递给调用者]必须移动到缓冲区的前面。
这里有一个测试程序可以做到这一点。这有点粗糙:
- 它忽略
mode
参数 - 如果没有以换行结束,那么它[可能]无法正确处理最后一行
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef DEBUG
#define dbgprt(_fmt...)
printf(_fmt)
#else
#define dbgprt(_fmt...)
do { } while (0)
#endif
char buf[128 + 1];
typedef struct {
int fd;
int eof;
size_t len;
char buf[4096];
} XFIL;
char *
fix(const char *str,int len)
{
static char buf[4096];
char *bp = buf;
if (len < 0)
len = strlen(str);
for (int idx = 0; idx < len; ++idx) {
int chr = str[idx];
if (chr == 0)
break;
if ((chr >= 0x20) && (chr <= 0x7E))
*bp++ = chr;
else
bp += sprintf(bp,"{%2.2X}",chr & 0xFF);
}
*bp = 0;
return buf;
}
XFIL *
xopen(const char *file,const char *mode)
{
XFIL *xf = calloc(1,sizeof(*xf));
xf->fd = open(file,O_RDONLY);
return xf;
}
char *
xfgets(char *buf,size_t maxlen,XFIL *xf)
{
size_t off = xf->len;
ssize_t rdlen;
size_t curlen;
char *bp;
char *nl;
char *ret = NULL;
dbgprt("xfgets: ENTER maxlen=%zu eof=%dn",maxlen,xf->eof);
while (1) {
dbgprt("xfgets: LOOP off=%zu eof=%dn",off,xf->eof);
// find newline if we have one
if (xf->len > 0)
nl = memchr(xf->buf,'n',xf->len);
else
nl = NULL;
// found a newline
if (nl != NULL) {
// get amount of data in buffer up to and including the newline
curlen = (nl - xf->buf) + 1;
dbgprt("xfgets: NLMATCH curlen=%zun",curlen);
// copy this out to caller's buffer (and add EOS)
memcpy(buf,xf->buf,curlen);
buf[curlen] = 0;
dbgprt("xfgets: RET buf='%s'n",fix(buf,-1));
// set up return pointer
ret = buf;
// get amount of data remaining in our buffer
curlen = xf->len - curlen;
dbgprt("xfgets: REMLEN curlen=%zun",curlen);
// slide this to the front of our buffer
memmove(xf->buf,nl + 1,curlen);
dbgprt("xfgets: HOLD bf='%s'n",fix(xf->buf,curlen));
xf->len = curlen;
break;
}
if (xf->eof)
break;
// read next chunk of file
bp = xf->buf + off;
rdlen = read(xf->fd,bp,16);
dbgprt("xfgets: READ rdlen=%zdn",rdlen);
if (rdlen < 0) {
ret = NULL;
xf->eof = 1;
break;
}
dbgprt("xfgets: DATA bp='%s'n",fix(bp,rdlen));
if (rdlen == 0)
xf->eof = 1;
// advance number of bytes in the hold buffer
xf->len += rdlen;
// advance offset into buffer
off += rdlen;
}
dbgprt("xfgets: EXIT ret=%pn",ret);
return ret;
}
int
main(void)
{
const char *file = "inp.txt";
FILE *fin = fopen(file,"r");
XFIL *xf = xopen(file,"r");
char buf[2][1000];
char *ret[2];
while (1) {
ret[0] = fgets(buf[0],1000,fin);
ret[1] = xfgets(buf[1],1000,xf);
printf("main: RET %p/%pn",ret[0],ret[1]);
if ((ret[0] != NULL) != (ret[1] != NULL))
break;
if (ret[0] == NULL)
break;
printf("BUF0: %sn",fix(buf[0],-1));
printf("BUF1: %sn",fix(buf[1],-1));
if (strcmp(buf[0],buf[1]) != 0) {
printf("errorn");
exit(1);
}
}
return 0;
}
这是测试输入:
abc
def
ghijklmnopqrstuvwxyz
qrm
这是[带有-DDEBUG
]的程序输出。我手动缩进了一点,以显示调用顺序:
xfgets: ENTER maxlen=1000 eof=0
xfgets: LOOP off=0 eof=0
xfgets: READ rdlen=16
xfgets: DATA bp='abc{0A}def{0A}ghijklmn'
xfgets: LOOP off=16 eof=0
xfgets: NLMATCH curlen=4
xfgets: RET buf='abc{0A}'
xfgets: REMLEN curlen=12
xfgets: HOLD bf='def{0A}ghijklmn'
xfgets: EXIT ret=0x7fff5d044d48
main: RET 0x7fff5d044960/0x7fff5d044d48
BUF0: abc{0A}
BUF1: abc{0A}
xfgets: ENTER maxlen=1000 eof=0
xfgets: LOOP off=12 eof=0
xfgets: NLMATCH curlen=4
xfgets: RET buf='def{0A}'
xfgets: REMLEN curlen=8
xfgets: HOLD bf='ghijklmn'
xfgets: EXIT ret=0x7fff5d044d48
main: RET 0x7fff5d044960/0x7fff5d044d48
BUF0: def{0A}
BUF1: def{0A}
xfgets: ENTER maxlen=1000 eof=0
xfgets: LOOP off=8 eof=0
xfgets: READ rdlen=16
xfgets: DATA bp='opqrstuvwxyz{0A}qrm'
xfgets: LOOP off=24 eof=0
xfgets: NLMATCH curlen=21
xfgets: RET buf='ghijklmnopqrstuvwxyz{0A}'
xfgets: REMLEN curlen=3
xfgets: HOLD bf='qrm'
xfgets: EXIT ret=0x7fff5d044d48
main: RET 0x7fff5d044960/0x7fff5d044d48
BUF0: ghijklmnopqrstuvwxyz{0A}
BUF1: ghijklmnopqrstuvwxyz{0A}
xfgets: ENTER maxlen=1000 eof=0
xfgets: LOOP off=3 eof=0
xfgets: READ rdlen=1
xfgets: DATA bp='{0A}'
xfgets: LOOP off=4 eof=0
xfgets: NLMATCH curlen=4
xfgets: RET buf='qrm{0A}'
xfgets: REMLEN curlen=0
xfgets: HOLD bf=''
xfgets: EXIT ret=0x7fff5d044d48
main: RET 0x7fff5d044960/0x7fff5d044d48
BUF0: qrm{0A}
BUF1: qrm{0A}
xfgets: ENTER maxlen=1000 eof=0
xfgets: LOOP off=0 eof=0
xfgets: READ rdlen=0
xfgets: DATA bp=''
xfgets: LOOP off=0 eof=1
xfgets: EXIT ret=(nil)
main: RET (nil)/(nil)