In the code below, I try to create an array of strings in shared memory , type in the first line from the keyboard, write it into an array in the child process, and display it on the screen in the parent process. When you output a string in the parent process, garbage is output instead of what I typed on the keyboard. What am I doing wrong and how should I do? The abundance of theoretical information in the response is welcome.

 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <sys/wait.h> #include <unistd.h> #include <string.h> #define SHMSIZE 100 int main() { int shmid; char** shm; if(fork() == 0) { shmid = shmget(2009, SHMSIZE, 0); shm = (char**)shmat(shmid, 0, 0); char** s = (char**) shm; char buf [100]; printf ("Enter string\n"); scanf("%s", buf); s[0] = new char [strlen(buf)]; s[0] = buf; printf ("<%s>\n",s[0]); shm [0] = s [0]; printf ("Child wrote <%s>\n",shm[0]); shmdt(shm); } else { shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT); shm = (char**)shmat(shmid, 0, 0); wait(NULL); printf ("Parent reads %s\n",shm [0]) ; shmdt(shm); shmctl(shmid, IPC_RMID, NULL); } return 0; } 

    2 answers 2

    Let's try to explain on the fingers.

    The fact is that the pointer is just a number. Modern operating systems have virtual memory , and this very number is only a byte number in this virtual memory. Each process has its own address space, and this means that each process has its own memory at 0x1234567890abcdef.

    From here an important conclusion follows: the transfer of pointers (which, as we remember, are numbers) between processes does not have much sense, the data from the address space of one process is not available in another process.

    The exception to this is shared memory: an area that is common to several processes. But this very common area may well have different addresses in these processes, so in any case, passing the pointer between processes does not help. Meaning has only an offset from the beginning of the shared memory .

    For your case, what are you doing? You place a pointer to another, non-shared memory in shared memory ( s[0] = new char [strlen(buf)]; ). How does this help? No, this pointer does not mean anything in another process.


    What to do? Well, if you need to transfer one line, then just write its contents (not a pointer!) To the beginning of the shared memory. Be sure to check the length!

    If you need to transfer an array of strings, then you have to invent some kind of serialization format. For example, such:

    1. At the beginning of the shared memory size_t field, in which lies the number of lines (let's call it N ).
    2. After it, the offset in bytes from the beginning of the shared memory for each of the rows, exactly N pieces.
    3. It is followed by lines whose offsets are defined in § 2, terminated by \0 for simplicity.

    Again, do not forget to make sure that the whole structure fits into a shared piece of memory.


    The record should look something like this (not tested, there is no Unix at hand):

     void* shm = ...; size_t N = 10; char** strings = ... ; *(size_t*)shm = N; size_t base_offset = sizeof(size_t) /* п. 1 */ + sizeof(size_t) * N /* п. 2 */; size_t* toc = (size_t*)shm + 1; for (size_t i = 0; i < N; i++) { toc[i] = base_offset; strcpy(strings[i], (char*)shm + base_offset); base_offset += strlen(strings[i]) + 1 /* trailing zero */; // неоптимально: пробегает строки дважды } 

    Well, reading:

     void* shm = ...; size_t N = *(size_t*)shm; size_t* toc = (size_t*)shm + 1; for (size_t i = 0; i < N; i++) { printf("%s", (char*)shm + toc[i]); } 

    Perhaps you should not bother with manual serialization and build bicycles, but use ready-made libraries for serialization (there are a lot of them, for example, Boost.Serialization ). Or worth it, that's for you to decide.

      The abundance of theoretical information in the response is welcome.

      You are incredibly lucky :)

      The book "UNIX: Interaction of Processes" by William Sievens - is available online .