C 编程:Segmentation Fault (Core Dumped)
C Programming: Segmentation Fault (Core Dumped)
我正在尝试编写的程序试图演示 IPC 如何在 Linux 上工作,但我不断收到核心转储错误。它编译得很好,并且会 运行 直到父进程中的最后一个输出语句。
我的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <err.h>
#include <sysexits.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define SHM_SIZE 15
int main (int argc, char ** argv[]) {
pid_t pid; //pid variable of type pid
int shmid; //shared memory id
int key = 1776; //randomly chosen key
char *shm; //shared memory name
int pipefd[2];
char buff;
pid = fork(); //creating child process
pipe(pipefd); //creating pipe
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return -1;
} else if (pid == 0) {
shmid = shmget(key, SHM_SIZE, 0);
shm = shmat(shmid, 0, 0);
char *n = (char *) shm;
printf("hello i am the child process. my pid is %d. what is your name?: ", getpid());
scanf("%s", n);
printf("\n");
///////////////////////////////////////////////////////////////////////////////////////
close(pipefd[1]);
printf("pipe opened on child end");
printf("\n");
while(read(pipefd[0], &buff, 1) > 0) {
write(1, &buff, 1);
}
write(1, "\n", 1);
close(pipefd[0]);
printf("pipe successfully closed");
printf("\n");
exit(EXIT_SUCCESS);
} else {
shmid = shmget(key, SHM_SIZE, 0777 | IPC_CREAT);
shm = shmat(shmid, 0, 0);
wait(NULL);
printf("\nThis is Child's Parent. My pid is %d. Nice to me you %s.\n", getpid(), shm);
printf("\n");
//////////////////////////////////////////////////////////////////////////////////////
close(pipefd[0]);
printf("pipe open on parent end");
printf("\n");
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
printf("pipe successfully closed");
wait(NULL);
exit(EXIT_SUCCESS);
}
return 0;
}
跟我的args[]有关系吗?比如我可以访问遥不可及的内存吗?或者正在尝试访问一些无效的指针?
非常感谢!
您正在从您创建的管道的同一端读取和写入。通常的做法是从 end [1] 读取并写入 end [0]。告诉我这是否有帮助。此外,通常的做法是不要在子进程和父进程之间进行太多操作。尝试在段(父段和子段)之间执行代码通常会以段错误告终,即使您的代码可以编译。
你的代码有几个问题
在 fork
之前创建管道 。您创建管道两次,一次用于
parent 进程和一个 child 进程。没意义,水管
创建的 child 不能被 parent 使用。管道必须已经
存在,以便 child 在 child 是时继承文件描述符
已创建。
通常 parent 创建共享内存而 child 获取 shmid
从 parent 执行 fork
。否则你将不得不同步
child 和 parent。所以我会先创建共享内存
fork
,以便 child 从 parent.
继承 shmid
在行 char *n = (char *) shm;
中不需要转换,shm
是
已经 char*
.
在 fork
之后的 parent 块中,您执行 wait(NULL);
然后继续
写入管道。这毫无意义,您同时屏蔽了 parent 和 child。
child 在 read
上阻塞,因为 parent 没有通过
管,还。 parent 在 wait
上阻塞,因为 child 永远不会退出,因此
不能通过管道发送任何东西。 parent必须先发送数据
通过管道,然后 wait
为 child 退出。
在child块你做scanf("%s", n);
,你不是在保护你
防止缓冲区溢出。 scanf("%14s", n)
会更好。还有你不是
检查 scanf
是否阅读了任何内容。如果用户按下
CtrlD然后stdin
关闭,scanf
失败。在这种情况下
n
可能不会被 '[=34=]'
终止,这会导致未定义的行为
当 parent 尝试打印它时。所以会更好:
if(scanf("%14s", n) != 1) // avoid buffer overflow
{
fprintf(stderr, "Child: cannot read from stdin\n");
n[0] = 0; // 0-terminating
}
在fork
之后的parent块中,你做了两次wait
,为什么?
你的main
错了,应该是
int main(int argc, char **argv);
parent通过管道将argv[1]
的内容发送到child,但是
你没有检查 argv[1]
是否不是 NULL
。在开始时使用它
程序:
if(argc != 2)
{
fprintf(stderr, "usage: %s string\n", argv[0]);
return 1;
}
所以正确的版本应该是:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <err.h>
#include <sysexits.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define SHM_SIZE 15
int main (int argc, char **argv) {
pid_t pid; //pid variable of type pid
int shmid; //shared memory id
char *shm; //shared memory name
if(argc != 2)
{
fprintf(stderr, "usage: %s string\n", argv[0]);
return 1;
}
int pipefd[2];
char buff;
// create shared memory before the fork,
// otherwise you will need to syncronize parent
// and child
pipe(pipefd); //creating pipe before the fork
// parent creates shared memory, child inherits shmid
// after fork
shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
pid = fork(); //creating child process
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1; // return -1 would be the same as return 255
} else if (pid == 0) {
shm = shmat(shmid, 0, 0);
char *n = shm; // shm is already a char*
printf("hello i am the child process. my pid is %d. what is your name?: ", getpid());
if(scanf("%14s", n) != 1) // avoid buffer overflow
{
fprintf(stderr, "Child: cannot read from stdin\n");
n[0] = 0; // 0-terminating
}
printf("\n");
///////////////////////////////////////////////////////////////////////////////////////
close(pipefd[1]);
printf("pipe opened on child end");
printf("\n");
printf("Parent sends: ");
fflush(stdout);
while(read(pipefd[0], &buff, 1) > 0) {
write(1, &buff, 1);
}
write(1, "\n", 1);
close(pipefd[0]);
printf("pipe successfully closed");
printf("\n");
exit(EXIT_SUCCESS);
} else {
shm = shmat(shmid, 0, 0);
close(pipefd[0]);
printf("pipe open on parent end");
printf("\n");
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
printf("pipe successfully closed");
// not we wait for child to exit
wait(NULL);
printf("\nThis is Child's Parent. My pid is %d. Nice to me you %s.\n", getpid(), shm);
printf("\n");
//////////////////////////////////////////////////////////////////////////////////////
exit(EXIT_SUCCESS);
}
return 0;
}
输出为:
$ ./b "message to child: stop playing video games!"
pipe open on parent end
hello i am the child process. my pid is 10969. what is your name?: Pablo
pipe opened on child end
Parent sends: message to child: stop playing video games!
pipe successfully closed
pipe successfully closed
This is Child's Parent. My pid is 10968. Nice to me you Pablo.
我正在尝试编写的程序试图演示 IPC 如何在 Linux 上工作,但我不断收到核心转储错误。它编译得很好,并且会 运行 直到父进程中的最后一个输出语句。
我的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <err.h>
#include <sysexits.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define SHM_SIZE 15
int main (int argc, char ** argv[]) {
pid_t pid; //pid variable of type pid
int shmid; //shared memory id
int key = 1776; //randomly chosen key
char *shm; //shared memory name
int pipefd[2];
char buff;
pid = fork(); //creating child process
pipe(pipefd); //creating pipe
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return -1;
} else if (pid == 0) {
shmid = shmget(key, SHM_SIZE, 0);
shm = shmat(shmid, 0, 0);
char *n = (char *) shm;
printf("hello i am the child process. my pid is %d. what is your name?: ", getpid());
scanf("%s", n);
printf("\n");
///////////////////////////////////////////////////////////////////////////////////////
close(pipefd[1]);
printf("pipe opened on child end");
printf("\n");
while(read(pipefd[0], &buff, 1) > 0) {
write(1, &buff, 1);
}
write(1, "\n", 1);
close(pipefd[0]);
printf("pipe successfully closed");
printf("\n");
exit(EXIT_SUCCESS);
} else {
shmid = shmget(key, SHM_SIZE, 0777 | IPC_CREAT);
shm = shmat(shmid, 0, 0);
wait(NULL);
printf("\nThis is Child's Parent. My pid is %d. Nice to me you %s.\n", getpid(), shm);
printf("\n");
//////////////////////////////////////////////////////////////////////////////////////
close(pipefd[0]);
printf("pipe open on parent end");
printf("\n");
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
printf("pipe successfully closed");
wait(NULL);
exit(EXIT_SUCCESS);
}
return 0;
}
跟我的args[]有关系吗?比如我可以访问遥不可及的内存吗?或者正在尝试访问一些无效的指针?
非常感谢!
您正在从您创建的管道的同一端读取和写入。通常的做法是从 end [1] 读取并写入 end [0]。告诉我这是否有帮助。此外,通常的做法是不要在子进程和父进程之间进行太多操作。尝试在段(父段和子段)之间执行代码通常会以段错误告终,即使您的代码可以编译。
你的代码有几个问题
在
fork
之前创建管道 。您创建管道两次,一次用于 parent 进程和一个 child 进程。没意义,水管 创建的 child 不能被 parent 使用。管道必须已经 存在,以便 child 在 child 是时继承文件描述符 已创建。通常 parent 创建共享内存而 child 获取
shmid
从 parent 执行fork
。否则你将不得不同步 child 和 parent。所以我会先创建共享内存fork
,以便 child 从 parent. 继承 在行
char *n = (char *) shm;
中不需要转换,shm
是 已经char*
.在
fork
之后的 parent 块中,您执行wait(NULL);
然后继续 写入管道。这毫无意义,您同时屏蔽了 parent 和 child。 child 在read
上阻塞,因为 parent 没有通过 管,还。 parent 在wait
上阻塞,因为 child 永远不会退出,因此 不能通过管道发送任何东西。 parent必须先发送数据 通过管道,然后wait
为 child 退出。在child块你做
scanf("%s", n);
,你不是在保护你 防止缓冲区溢出。scanf("%14s", n)
会更好。还有你不是 检查scanf
是否阅读了任何内容。如果用户按下 CtrlD然后stdin
关闭,scanf
失败。在这种情况下n
可能不会被'[=34=]'
终止,这会导致未定义的行为 当 parent 尝试打印它时。所以会更好:if(scanf("%14s", n) != 1) // avoid buffer overflow { fprintf(stderr, "Child: cannot read from stdin\n"); n[0] = 0; // 0-terminating }
在
fork
之后的parent块中,你做了两次wait
,为什么?你的
main
错了,应该是int main(int argc, char **argv);
parent通过管道将
argv[1]
的内容发送到child,但是 你没有检查argv[1]
是否不是NULL
。在开始时使用它 程序:if(argc != 2) { fprintf(stderr, "usage: %s string\n", argv[0]); return 1; }
shmid
所以正确的版本应该是:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <err.h>
#include <sysexits.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define SHM_SIZE 15
int main (int argc, char **argv) {
pid_t pid; //pid variable of type pid
int shmid; //shared memory id
char *shm; //shared memory name
if(argc != 2)
{
fprintf(stderr, "usage: %s string\n", argv[0]);
return 1;
}
int pipefd[2];
char buff;
// create shared memory before the fork,
// otherwise you will need to syncronize parent
// and child
pipe(pipefd); //creating pipe before the fork
// parent creates shared memory, child inherits shmid
// after fork
shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
pid = fork(); //creating child process
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1; // return -1 would be the same as return 255
} else if (pid == 0) {
shm = shmat(shmid, 0, 0);
char *n = shm; // shm is already a char*
printf("hello i am the child process. my pid is %d. what is your name?: ", getpid());
if(scanf("%14s", n) != 1) // avoid buffer overflow
{
fprintf(stderr, "Child: cannot read from stdin\n");
n[0] = 0; // 0-terminating
}
printf("\n");
///////////////////////////////////////////////////////////////////////////////////////
close(pipefd[1]);
printf("pipe opened on child end");
printf("\n");
printf("Parent sends: ");
fflush(stdout);
while(read(pipefd[0], &buff, 1) > 0) {
write(1, &buff, 1);
}
write(1, "\n", 1);
close(pipefd[0]);
printf("pipe successfully closed");
printf("\n");
exit(EXIT_SUCCESS);
} else {
shm = shmat(shmid, 0, 0);
close(pipefd[0]);
printf("pipe open on parent end");
printf("\n");
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
printf("pipe successfully closed");
// not we wait for child to exit
wait(NULL);
printf("\nThis is Child's Parent. My pid is %d. Nice to me you %s.\n", getpid(), shm);
printf("\n");
//////////////////////////////////////////////////////////////////////////////////////
exit(EXIT_SUCCESS);
}
return 0;
}
输出为:
$ ./b "message to child: stop playing video games!"
pipe open on parent end
hello i am the child process. my pid is 10969. what is your name?: Pablo
pipe opened on child end
Parent sends: message to child: stop playing video games!
pipe successfully closed
pipe successfully closed
This is Child's Parent. My pid is 10968. Nice to me you Pablo.