【问题标题】:Infinite loop caused by perror scanf through a pipe由 perror scanf 通过管道引起的无限循环
【发布时间】:2017-10-21 16:40:34
【问题描述】:

我一直在编写一个 c 程序,它将数据从一个文件传输到下一个文件,但是它一直是无限循环的。

到目前为止我发现了什么。无限循环是在文件 c1.c 上引起的,其中 perror(或 stderr)跳过了 scanf。如果 scanf 确实有效。程序无限循环进一步沿着轨道打印出 perror,即使它超过了那个部分!

我的代码在下面

控制器.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>

int main(int ac, char**av)
{
int pipez[2];
int piped[2];
int status;
pid_t pid;

if (pipe (pipez) == -1){
perror("could not make pipe");
return 1;
}

if ((pid = fork()) == -1){
perror("fork");
return 1;
}

if(pid == 0){
close(pipez[1]);
dup2(pipez[0],0);
close(pipez[0]);
execvp("./c1",av);
perror("demo);
_exit(1);
}
else{
close(pipez[0]);
dup2(pipez[1],1);
close(pipez[1]);
execvp("./c2",av);
perror("demo");
exit(1);
}

waitpid(pid,&status,0);
if(WIFEXITED(status)){
printf("[%d] TERMINATED (Status: %d)\n", pid, WEXITSTATUS(status));
}

if(pipe (piped) == -1){
perror("could not make pipe");
return 1;
}

if((pid = fork()) == -1){
perror("fork");
return 1;
}

if (pid == 0){
close(piped[1]);
dup2(piped[0],0);
close(piped[0]);
execvp("./c2", av);
perror("demo");
_exit(1);
}
else{
close(piped[0]);
dup2(piped(piped[1],1);
close(piped[1]);
execvp("./c3",av);
perror("demo");
exit(1);
}

waitpid(pid, &status, 0);
if (WIFEXITED(status)){
printf("[%d] TERMINATED (Status: %d)\n", pid, WEXITSTATUS(status));
}

return 0;
}

c1.c

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

#define BUFSIZE 256

//This program is causing infinite loop, tried fflush and fgets and scanf
// It will run independently but will loop via the pipe

int main(int a, char**av){
char store[BUFSIZE];
memset(store, '\0', sizeof(store));
while(strcmp(store, "exit!") != 0){

perror("Please enter next line of input (type 'exit!' to stop) \n"); //This repeats itself infinitely
fgets(store, BUFSIZE, stdin);
printf("%s",store); // This also repeats itself dependant on where i put 
//fflush or another printf. Repeated outputs occur in blocks
}

return 0;
}

c2.c

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

#define BUFSIZE 256

char *strlwr(char *str);

int main(int ac, char**av){
char store[BUFSIZE];

while(strcmp(store, "exit!") != 0){
scanf("%s", store);
printf("%s", strlwr(store));
}

return 0;
}

char *strlwr(char *str){
unsigned char *p = (unsigned char *)str;

while(*p){
*p = tolower((unsigned char)*p);
p++;
}

return str;

}

c3.c

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

#define BUFSIZE 256

int main(int ac, char**av){
char store[BUFSIZE];
int n = 0;

while(strcmp(store, "exit!") != 0{
scanf("%s",store);
printf("Line %d: %s\n",n,store);
n++;

}

return 0;
}

【问题讨论】:

  • memset(store, '/0', sizeof(store)); ----> memset(store, '\0', sizeof(store));
  • 感谢 LP,我在代码中开始使用它,但我必须在帖子中输入错误。我现在已经编辑了,再次感谢!
  • 请注意,perror() 旨在根据errno 的值在标准错误上打印错误消息——它不是通用的提示功能。
  • 嗨乔纳森,我使用 perror 因为管道,使用使用标准输出的函数只会将其发送到下一个程序/文件。但是,我会寻找替代方案,因为该程序仍在大量打印错误和输出
  • 正常的选择就是fprintf(stderr, …)

标签: c linux pipe stdin infinite-loop


【解决方案1】:

fgets'\n' 字符留在store 缓冲区中,因此,最简单的解决方法是将'\n' 添加到比较字符串中:

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

#define BUFSIZE 256

//This program is causing infinite loop, tried fflush and fgets and scanf
// It will run independently but will loop via the pipe

int main(int a, char**av)
{
    char store[BUFSIZE];
    memset(store, '\0', sizeof(store));
    while (strcmp(store, "exit!\n") != 0)
    {

        perror("Please enter next line of input (type 'exit!' to stop) \n"); //This repeats itself infinitely
        fgets(store, BUFSIZE, stdin);
        printf("%s", store); // This also repeats itself dependant on where i put
                             // fflush or another printf. Repeated outputs occur in blocks
    }

    return 0;
}

此外,如您所见,init value '/0' 是不可接受的;它必须是“\0”。您的编译器可能会告诉您类似

test.c: In function ‘main’:
test.c:242:16: warning: multi-character character constant [-Wmultichar]
  memset(store, '/0', sizeof(store));
                ^

顺便说一句,memset,在这种情况下是无用的,因为fgets 完成了所有工作,但无论如何,如果您希望将缓冲区设置为 nul,只需声明:

char store[BUFSIZE] = {0};

使用fgets 的最佳解决方案是(显然)始终管理左边的换行符:

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

#define BUFSIZE 256

//This program is causing infinite loop, tried fflush and fgets and scanf
// It will run independently but will loop via the pipe

int main(void)
{
    char store[BUFSIZE] = {0};
    char *pos;
    while (strcmp(store, "exit!") != 0)
    {

        perror("Please enter next line of input (type 'exit!' to stop) \n"); //This repeats itself infinitely
        fgets(store, BUFSIZE, stdin);

        if ((pos = strchr(store, '\n')) != NULL)
            *pos = '\0';
        else
            fprintf(stderr, "String too long!\n");

        printf("%s", store); // This also repeats itself dependant on where i put
                             // fflush or another printf. Repeated outputs occur in blocks
    }

    return 0;
}

【讨论】:

  • @JonathanLeffler 你比我的拼写检查器快;)谢谢
  • 大家好,还是没有运气。 fgets 允许我现在输入输入,但是当我输入退出时!问题再次出现。如果我将“exit\n”添加到 c2,问题就会停止,但它只是不断要求输入并且不会退出循环。我已经添加了建议的代码。也许这是管道的问题?
  • @rowboat 如你所见HERE 我发布的代码就像一个魅力
  • 单个程序 c1.c 可以正常工作,但是当通过管道放置时,它会输出重复的行,例如 perror 和 store 的内容,我认为它可能是缓冲区溢出或类似的东西。我在测试时注意到的几件事。 c1.c 在第一次调用后退出它的循环,即使退出!没有输入。我在想的另一件事是程序可能被错误地管道传输。
猜你喜欢
  • 2012-04-09
  • 2012-06-03
  • 2021-09-28
  • 1970-01-01
  • 2012-10-05
  • 2016-06-05
  • 2011-07-14
  • 2013-10-12
  • 1970-01-01
相关资源
最近更新 更多