gpt4 book ai didi

c - 如何在我的程序中使用 getc() 而不是 fgets()

转载 作者:行者123 更新时间:2023-12-01 20:09:19 26 4
gpt4 key购买 nike

所以我正在写它应该做到这一点例如

              This info is supposed to
be flipped back
for this code.

empty line was above this one.

会变成

to supposed is info This
back flipped be
code. this for
one. this above was line empty

现在我有一个函数可以完美地做到这一点,但我的教授告诉我要逐个字符地读取,然后在遇到新行时处理一行。然后继续到下一行,直到 EOF。

另一方面,我有一个 fgets,我加载整个输入/文件。然后我在我的函数中处理这个问题。另一方面,如果一行长度超过 80 个字符,那么我不应该处理它。

这是我的工作代码,但如何转换它以便它使用 getc() 而不是 fgets?谢谢

void reverser(FILE *input){
char c[82]; //Character size limited per line
if(outputFlag)
fp = freopen(fileName, "a+", stdout);
while (fgets(c, sizeof c, input)!=NULL){
int counter =0;
int x = 0;
while(*(c+x)=='\t' || *(c+x)==SPACE)
x++;
if(*(c+x) == '\n')
continue;
char *pCar[80];
int i, n = 0;
char *tok = strtok(c, " \t\n");
while (tok != NULL && n < 80){
*(pCar+n++) = tok;
tok = strtok(NULL, " \t\n");
}
for(i = n-1; i>=0; --i){ //Counting the char length of the lines
counter+=(int)strlen(*(pCar+i));
if(i)
counter++;
}
if(counter>80){ //Throw error if character length is > 80
fprintf(stderr, "LINE TOO LONG\n");
returnVal = 1;
continue;
}
for(i = n-1; i>=0; --i){
printf("%s", *(pCar+i));
if(i)
putchar(' ');
}
printf("\n");
}
fclose(input);
}

我很想得到一些提示。

最佳答案

这段代码似乎或多或少对我有用。

源文件z.c

#include <stdio.h>
#include <string.h>

char *read_line(char *buffer, size_t buflen, FILE *fp);
void reverser(FILE *input);

char *read_line(char *buffer, size_t buflen, FILE *fp)
{
int c;
char *data = buffer;
char *end = buffer + buflen - 1;
while (data < end && (c = getc(fp)) != '\n')
{
if (c == EOF)
{
*data = '\0';
return (data == buffer) ? NULL : buffer;
}
*data++ = c;
}
if (data < end)
{
*data++ = c;
*data = '\0';
}
else
{
// Overlong line - report error, read and discard to EOL
// or EOF, and return empty string (not even newline).
fprintf(stderr, "Line too long: discarded!\n");
while ((c = getc(fp)) != EOF && c != '\n')
;
*buffer = '\0';
}
return buffer;
}

void reverser(FILE *input)
{
char c[82];
while (read_line(c, sizeof c, input) != NULL)
{
int x = 0;
while (c[x] == '\t' || c[x] == ' ')
x++;
if (c[x] == '\n' || c[x] == '\0')
continue;
char *pCar[80];
int i, n = 0;
char *tok = strtok(c, " \t\n");
while (tok != NULL && n < 80)
{
*(pCar + n++) = tok;
tok = strtok(NULL, " \t\n");
}
for (i = n - 1; i >= 0; --i)
{
printf("%s", *(pCar + i));
if (i)
putchar(' ');
}
printf("\n");
}
// fclose(input); // Don't close what you didn't open!
}

int main(void)
{
reverser(stdin);
return 0;
}

我对 reverser() 进行了最小的更改,删除了不再相关的代码,使用 c[x] 代替 *(c + x) 因为它更容易键入和阅读,用 ' ' 替换 SPACE,删除代码以重新打开标准输出等。

该程序使用以下方式干净地编译:

 gcc -Wall -Wextra -Werror z.c -o z

(在带有 GCC 5.1.0 的 Ubuntu 14.04 衍生版本上进行测试。)

示例输出:
$ ./z
pedagogical anti-orthodoxy grammatically correct infelicitous nonsense munged with catatonic isotopes of prejudice and grunge lead to positive recognition of abusive memes in the genetic diversity of alphabets.
Line too long: discarded!
pedagogical anti-orthodoxy grammatically correct infelicitous nonsense
nonsense infelicitous correct grammatically anti-orthodoxy pedagogical
munged with catatonic isotopes of prejudice and grunge lead
lead grunge and prejudice of isotopes catatonic with munged
to positive recognition of abusive memes in the genetic diversity of alphabets.
alphabets. of diversity genetic the in memes abusive of recognition positive to
$

答案的上下文

最初,有很多与该问题相关的评论,寻求并获得问题的说明并概述解决方案。这些评论已全部删除 - 请参阅此 MSO question 。幸运的是,我开发答案的浏览器一夜之间保留了对该问题的评论。我并不是说这些评论很棒;我并不认为这个问题很棒;我并不声称我的答案很好。我同意 JQ143 的许多评论应该是对问题的编辑。我确实断言这些评论为我的回答提供了必要的背景,不应该被批量删除。

下面的评论并非逐字复制;它们是经过精心策划的。 wildplasser 的几条评论已被省略。

乔纳森·莱夫勒评论道:

There are similar questions on SO already. Why would you want to use getc() instead of fgets()? You need to process whole lines, so reading whole lines makes a lot of sense. One easy way around it is to write your own function, maybe char *read_line(char *buffer, size_t buflen, FILE *fp) that uses getc() but simulates fgets(). More likely, he has in mind that you'll use getc() to read characters into the first word, then the second, then ..., and when you hit EOL (newline), you print out the saved words in reverse order, zero things, and repeat.

我注意到BLUEPIXYanswer实质上实现了“使用 getc() 一次读取一个单词”版本的代码。

ChuckCottrill注意到:

The instructor wants you do demonstrate that you know how to build your own fgets() function using the getc() function as a base, or perhaps gather one word at a time, pushing those words onto a stack, and then pop them from the stack and emit them.

JQ143评论(但理想情况下应该修改问题以说明):

So what he basically wants is to keep adding characters to an array until you hit newline. Once you hit newline you can process that array and print them backwards. Then repeat this with character starting after that old newline... Any idea how I can just use getc()? He said it should be easy to fix.

@ChuckCottrill my professor is saying the fgets won't work with this program. He said it'll break, which I don't see how it could.

我注意到:

That's what my proposed read_line() does and the existing fgets() does. Ignoring buffer overflow checking, that's trivial:

char *read_line(char *buffer, size_t buflen, FILE *fp)
{
int c;
char *data = buffer;
while ((c = getc(fp)) != '\n')
{
if (c == EOF)
{
*data = '\0';
return (data == buffer) ? 0 : buffer;
}
*data++ = c;
}
*data++ = c;
*data = '\0';
return buffer;
}

Adding buffer overflow checking is not difficult, but is left as an exercise for you. If you need to ignore lines that are too long, or read and discard the excess material if the line is too long, that is also easily done.

(该代码在我的正常编译器选项下无法编译,因为未使用 buflen。)

JQ143回复:

I am sorry but I am having a hard time figuring out how to incorporate that into my program.

我的回复是:

Change: while (fgets(c, sizeof c, input)!=NULL){ to while (read_line(c, sizeof c, input)!=NULL){

Note that using the name c for an array of char is not conventional; c normally denotes a single char variable: char c;.

Also note that the code if(outputFlag) fp = freopen(fileName, "a+", stdout); makes this function logically incohesive. The calling code should handle the redirection. It can either pass the output file stream to this function (so void reverser(FILE *input, FILE *output)) or arrange it so that stdout is modified with freopen(). But this function should not be accessing the global variables fileName and outputFlag.


jxh注意到:

See: fgets implementation (K&R); it was the top link of my Google search.

As to how the program might fail, if a line length N is longer than 80 characters, it looks like you will reverse the last (N % 81) bytes of the line (81 since sizeof(c) is 82).

JQ143回复:

@jxh so if a line length is greater than 80. It will just throw an stderr saying line too long. Which is actually part of the program.

jxh 回应:

You print an error, but you continue the loop.

JQ143:

@jxh Oh..according to my professor, I have to process lines that are less than 80 but throw an error for those that are longer.

jxh:

You process the remaining lines, yes. But, you also process the rest of the currently too long line. If the line was 100 bytes long, you read in 81 bytes of it. When you determine the line is too long, you print your error, and continue. When you continue, you end up reading in 19 more bytes of the too long line. 100 % 81 is 19.

JQ143:

@jxh you are actually right. I'll try to fix that.


JQ143:

Thank you!, but upon doing so [changing fgets() to read_line()] my program went into a crazy infinite loop.

我反驳道:

I just compiled the code extracted from my comment (the read_line() function), and it seems to work OK as long as you don't have overlong lines. A revised version of the code is:

char *read_line(char *buffer, size_t buflen, FILE *fp)
{
int c;
char *data = buffer;
char *end = buffer + buflen - 1;
while (data < end && (c = getc(fp)) != '\n')
{
if (c == EOF)
{
*data = '\0';
return (data == buffer) ? 0 : buffer;
}
*data++ = c;
}
if (data < end)
*data++ = c;
else
ungetc(c, fp);
*data = '\0';
return buffer;
}

该函数的这种变体会在一行中留下额外的数据,以便下次调用该函数时读取,就像 fgets() 所做的那样。

JQ143:

Any hints on how to deal with lines longer than 80 chars?

Using your variable name, I'd use

char c[4096];
while (read_line(c, sizeof(c), input) != 0)
{
if (strlen(c) > 80)
{
fprintf(stderr, "Too long at %zu (line <<%s>>)\n", strlen(c), c);
continue; /* or break; */
}
...

reading lines up to 4 KiB and only processing ones that are short enough. That runs the (rather small) risk that you'll get a line of 4150 bytes, and reject the first 4095 bytes, but process the remainder as a 55 byte line. If that's not acceptable, modify the code in read_line() to detect overlong input (passing an 82 byte buffer), and have it gobble to EOL or EOF when necessary.

这基本上肯定了 @jxh 关于行太长时代码行为的说法,并概述了解决该问题的方法。

JQ143:

@JonathanLeffler So I pretty much want to throw an stderr (just once) if I detect a sentence is longer than 80 chars. I think reading it up to 80 and not reading the rest is a good way. But how can I do that in read_line() instead of doing that weird counter stuff in my other method? I also wanna thank you for helping me. I appreciate it so much.

此时,已经可以给出答案了;规范足够清晰——尽管信息应该在问题中而不是评论中。

查克科特里尔指出:

An interesting variant solution would be to build a readline function that would increase the allocated space (see realloc) as the buffer size was exhausted...

这就是 POSIX getline() .

chux noted ,我的代码不处理零的 buflen 。在我看来,sizeof(object) 在 C 中永远不会产生 0,所以你必须尝试遇到这个问题。对该函数的一项粗略修改是:

assert(*buffer != 0 && buflen != 0 && fp != 0);
if (buffer == 0 || buflen == 0 || fp == 0)
return 0;

assert强制在开发环境中正确使用;该测试模拟生产环境中的 EOF,避免运行时出现灾难性的错误行为。

关于c - 如何在我的程序中使用 getc() 而不是 fgets(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29931567/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com