c -进程之间的管道



我试着写一个程序,把一串字符变成大写字母。父进程应该接受字符串,并通过管道将其发送给子进程。然后,子进程应该从管道中读取,将所有字母转换为大写字母,并将其打印到控制台上。我真不明白为什么我的管子坏了。这可能是一个问题,当父进程甚至没有在管道中写入任何内容时,子进程试图读取管道。

提前谢谢你。

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#define BUF 64
/*
Aufgabe: 
Elternprozess: Gibt einen Array mit Klein- und Großbuchstaben mit einer pipe an dem Kindprozess weiter
Kindprozess: Verwanldelt alle Zeichen in Großbuchstaben
*/
int main(void) {
pid_t pid;
int fd[2];
pipe(fd);
char *buffer = malloc(sizeof(char)*BUF);
switch(pid = fork()) {
case -1:
perror("FEHLER BEI FORKn");
break;
case 0: //Kindprozess
close(fd[1]);
char c;
int i = 0;
while(1) {
read(fd[0], &c, 1);
if(c == '') {
break;
} else if(c > 64 || c < 123) {
buffer[i] = c;
i++;
}
}
for(int i = 0; i < BUF; i++) {
if(buffer[i] > 96 && buffer[i] < 123) {
buffer[i] -= 32;
}
}
printf("Die Zeichen in Großbuchstaben sind:nn");
for(int i = 0; i < BUF; i++) {
if(buffer[i] != 0 && buffer[i] != 48) {
printf("%c", buffer[i]);
printf("   ");
}
}
free(buffer);
break;
default: //Elternprozess
close(fd[0]);
char string1[] = "a b c d ";
memset(buffer, 0, BUF);
strcpy(buffer, string1);
int len = strlen(buffer) + 1;
int n;
int total = 0;
while(n < len) {
n = write(fd[1], buffer, strlen(buffer));
if(n < 0) {
perror("FEHLER BEIM SENDENn");
break;
}
total += n;
}
printf("Nachricht gesendet.n");

free(buffer);
wait(NULL);
break;
}
}   

问题是读进程一直读到NUL字符,但这永远不会出现,缓冲区溢出,子进程死亡。

NUL字符永远不会被读取,因为它永远不会被写入。仔细看一下写循环,稍微简化一下是:

int len = strlen(buffer) + 1;
int total = 0;
while(n < len) {
n = write(fd[1], buffer, strlen(buffer));
total += n;
}

请注意,您在len中计算要写入的字节数,包括NUL,但随后您写入strlen(buffer)字节,不包含计数NUL。然后将写入的字节添加到total,但不使用该变量。因此,您正在无休止地编写不带NUL的字符串副本。

解决方案是这样的:

let len = strlen(buffer) + 1;
int total = 0;
while(total < len) {
n = write(fd[1], buffer + total, len - total);
if (n < 0) { /*...*/ }
total += n;
}

即使有了上面的更正,您的子进程仍然调用未定义行为写入超出字符串末尾的内容。当你应该只迭代i次时,你迭代了BUF次。此外,您正在使用:

在孩子中阴影i
int i = 0;
while(1) {
read(fd[0], &c, 1);
if(c == '') {
break;
} else if(c > 64 || c < 123) {
buffer[i] = c;
i++;
}
}
for(int i = 0; i < BUF; i++) {
...
}
printf("Die Zeichen in Großbuchstaben sind:nn");
for(int i = 0; i < BUF; i++) {
...

如果您将-Wshadow添加到gcc的编译字符串中,您总是可以捕获此问题。此外,只要确保buffer以空字符结尾,然后在buffer[i]上迭代,直到到达空字符,就可以纠正迭代问题。这简化了你的逻辑。

下面的迭代for(i = 0; buffer[i]; i++)来避免这个问题。这是遍历以空结束的字符串中的字符的正确方法,而不必事先知道长度(这就是空结束字符的作用)

(编辑:-组合循环,用ctype.h宏简化)

case 0: //Kindprozess
close(fd[1]);
char c;
int i = 0;
while(1) {
read(fd[0], &c, 1);
if(c == 0) {
break;
}
else if (isalpha ((unsigned char)c)) {        /* is A-Za-z ? */
buffer[i] = toupper ((unsigned char)c);   /* make uppwer case */
i++;
}
}
buffer[i] = 0;    /* nul-terminate at i */
printf("Die Zeichen in Großbuchstaben sind:nn");
for(i = 0; buffer[i]; i++) {
printf("%*c", i ? 3 : 0, buffer[i]);    /* write 3 spaces except 1st */
}
putchar ('n');
free(buffer);
break;

尽可能避免使用MagicNumbers。不要使用48,而要使用'0'(这对您使用它的方式没有意义)。当你说'a'时不要说>96,当你说'z'时不要说<123。使用文字字符代替——可读性更强。

另外,包括ctype.h并利用为isalpha()isupper()islower()等提供的宏。比>96<123更具可读性。

实际上,如果使用ctype.h宏,则不需要对字符值进行任何手动测试。在您的代码中,您只包含从父节点发送的alpha字符。您可以简单地使用isalpha()来实现此目的。

如果您使用toupper()宏,则不需要测试何时转换为大写字母——它只会将小写字母转换为大写字母,并在内部提供测试。

在输出行末尾留下尾随空格不是一个好主意。您可以通过在除第一个字符输出之外的所有字符前写3个空格来控制输出字符之间的3个空格。printf()中一个简单的三元制字段宽度使其变得简单,例如

printf("%*c", i ? 3 : 0, buffer[i]);

把这个和另一个答案的更正一起试一试,你的程序应该像你期望的那样运行。

使用/输出示例

$ ./bin/pipe-fork-uppercase
Nachricht gesendet.
Die Zeichen in Großbuchstaben sind:
A  B  C  D

额外的想法

你的代码中还有其他一些地方有点尴尬。

  • 虽然动态分配没有什么问题,但是对于64字节,使用堆栈上的自动存储的简单数组声明如果可以,并且在完成时不需要跟踪和free()内存。
  • sizeof(char)被定义为1,所以如果你分配(例如malloc(BUF)是所有需要的),它可以在调用malloc()时被省略,
  • buffer在父进程中不需要。您可以简单地将string1的内容写入管道。buffer只能在子进程中声明自动存储持续时间。很好地定义了常量BUF
  • 当从程序中写入输出时,不要忘记在最终输出后输出'n'以使程序符合POSIX。如果不这样做,在任何非命名窗口的操作系统中都会出现下一个终端提示符。putchar('n');是所有需要的。

把它们放在一起,用char string1[] = "a b c d*E_F+G-h ";使字符串传递更有趣一点,你会有:

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>
#define BUF 64
/*
Aufgabe: 
Elternprozess: Gibt einen Array mit Klein- und Großbuchstaben mit einer pipe an dem Kindprozess weiter
Kindprozess: Verwanldelt alle Zeichen in Großbuchstaben
*/
int main (void) {
pid_t pid;
int fd[2];
pipe (fd);
switch (pid = fork()) {
case -1:
perror ("FEHLER BEI FORKn");
break;

case 0: //Kindprozess
close (fd[1]);

char c, buffer[BUF];
int i = 0;

while (1) {
read (fd[0], &c, 1);
if (c == 0) {
break;
}
else if (isalpha ((unsigned char)c)) {      /* is A-Za-z ? */
buffer[i] = toupper ((unsigned char)c);   /* make uppwer case */
i++;
}
}

buffer[i] = 0;    /* nul-terminate at i */
printf ("Die Zeichen in Großbuchstaben sind:nn");

for (i = 0; buffer[i]; i++) {
printf ("%*c", i ? 3 : 0, buffer[i]);   /* write 3 spaces except 1st */
}
putchar ('n');   /* tidy up with newline */
break;

default: //Elternprozess
close (fd[0]);

char string1[] = "a b c d*E_F+G-h ";
int len = strlen (string1) + 1,
n,
total = 0;

while (total < len) {
n = write (fd[1], string1 + total, len - total);
if (n < 0) {
perror ("FEHLER BEIM SENDENn");
break;
}
total += n;
}
printf ("Nachricht gesendet.n");

wait (NULL);
break;
}
}   

使用/输出示例

$ ./bin/pipe-fork-uppercase
Nachricht gesendet.
Die Zeichen in Großbuchstaben sind:
A  B  C  D  E  F  G  H

相关内容

  • 没有找到相关文章

最新更新