Thread: Initialize a 1D or 2D array in shared memory (POSIX)

  1. #1
    Registered User
    Join Date
    Dec 2014
    Posts
    3

    Initialize a 1D or 2D array in shared memory (POSIX)

    I am trying to initialize a 2D char array of strings into POSIX shared memory to be shared between 3 other processes. There are plenty of tutorials on how to use a pointer to share a single string or an integer between processes, but I could find no examples on how to initialize 1D or 2D arrays using mmap(). I have posted what I have so far below. It is the first program, which creates the shared memory object and initialize the array char files[20][2][100] with the value files[0][0][0] = '\0'.

    What is the proper method to initialize and share an array in C?

    For context, I coded a simple version of this project (at the suggestion of helpful S.O. gurus) which does not use shared memory and combines all 4 processes (separated by /**********/) into one. It's below.


    CODE SO FAR: (program initializes shared memory object and array)
    Code:
    #include<fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/shm.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    
    int main (int argc, char *argv[])
    {
        char files [20][2][100]; 
    
    
        /* the size of shared memory object */
        int size = sizeof(files);
    
        /* name of the shared memory object */
        const char *name = "/PROJ4_SHARED_MEM";
    
        /* shared memory file descriptor */
        int shm_fd;
    
        /* pointer to shared memory obect */
        void *ptr;
    
        /* create the shared memory object */
        shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    
        /* configure the size of the shared memory object */
        ftruncate(shm_fd, size);
    
        /* memory map the shared memory object */
        ptr = mmap(0, size, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    
        /* save array to the shared memory object. */
        /*****WHERE I LOSE IT*****/
    
        return 0;
    }


    CONTEXT PROGRAM: (not POSIX)
    Code:
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    
    int main (int argc, char *argv[])
    {
        char files [20][2][100]; 
        files [0][0][0] = '\0';
        char file_name[100];
    
        char file_contents[100];
        char search[100];
    
        char answer;
        int again = 0;
        int counter;
        int i = 0;
    
        /**************************************************/
    
        while (again == 0)
        {
            printf("Enter a filename:  ");
            scanf("%s", &file_name);
            getchar();
            printf("Enter file contents (string):  ");
            fgets (file_contents, 100, stdin);
    
            for (i = 0; i < 20; i++)
            {
                if (files[i][0][0] == '\0')
                {
                    strcpy(files[i][0],file_name);
                    strcpy(files[i][1],file_contents);
                    files [i+1][0][0] = '\0';       
                    break;
                }
                else if (i == 19)
                {
                    printf("ERROR: The directory is full.\n\n");
                }
            }
    
            counter++; 
    
            printf("Save another file y/n ?:  ");
            scanf(" %c", &answer);
    
            if (answer == 'n')
            {
                again = 1;
            }
    
        }
        printf("\n\n");
        again = 0;
    
        /**************************************************/
    
        printf("You have saved the following files:\n");
        for (i = 0; i < 20; i++)
        {
            if (files[i][0][0] == '\0')
            {
                break;
            }
    
            printf("%s \n", files[i][0]);
        }
        printf("\n\n");
    
        /**************************************************/
    
        printf("Would you like to open a file? (y/n) ?:  ");
        scanf(" %c", &answer);
        if (answer == 'n')
            again = 1;
    
        while (again == 0)
        {
            printf("Enter a filename:  ");
            scanf(" %s", &file_name);
    
            for (i = 0; i < 20; i++)
            {
                if (strcmp(files[i][0], file_name) == 0)
                {
                    printf("%s \n", files[i][1]);       
                    break;
                }
                else if (i == 19)
                {
                    printf("ERROR: The file was not found.\n\n");
                }
            }
    
            printf("Search for another file (y/n) ?:  ");
            scanf(" %c", &answer);
    
            if (answer == 'n')
            {
                again = 1;
            }
            printf("\n\n");
        }
    
    
        getchar();
    
        return 0;
    }
    Last edited by Louis Sutter; 12-08-2014 at 11:52 AM.

  2. #2
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Multi-dimensional arrays are initialized at the same time as declaring them, as in:
    Code:
    char x[20][100] = {0};
    As far as shared memory goes, it is conceptually the same as any client-server program. First off you'd code a server program that uses shmget() to create a shared memory segment; and shmat() to attach it to its address space. Then you'd initialize it as you'd initialize any other variable of that type. Finally code a client program that connects to that shared memory ID and reads what the server program put in there.

  3. #3
    Registered User
    Join Date
    Dec 2014
    Posts
    3
    Quote Originally Posted by itCbitC View Post
    As far as shared memory goes, it is conceptually the same as any client-server program. First off you'd code a server program that uses shmget() to create a shared memory segment; and shmat() to attach it to its address space. Then you'd initialize it as you'd initialize any other variable of that type. Finally code a client program that connects to that shared memory ID and reads what the server program put in there.
    Thanks.
    The call that creates the shared object in our book is mmap(). Apparently this is the newer way of doing it, from what I've read. In an example void* ptr = mmap(.....).The pointer is then used to add the strings "Hello" and "World". The pointer is incremented the length of the string after adding each string to memory.

    Code:
    /* create the shared memory object */
    shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    
    /* configure the size of the shared memory object */
    ftruncate(shm fd, SIZE);
    
    /* memory  map the  shared  memory  object */
    ptr = mmap(0, SIZE,  PROT_WRITE,   MAP_SHARED,  shm_fd, 0);
    
    /* write to  the  shared  memory  object */
    sprintf(ptr,"%s",message 0); 
    ptr += strlen(message 0); 
    sprintf(ptr,"%s",message 1);
    ptr += strlen(message 1);
    All examples use the void pointer, but its to add a single string or integer. How can I make this work using mmap() with an array?
    Last edited by Louis Sutter; 12-08-2014 at 12:51 PM.

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Note: shared memory is outside scope of the C standard. This really belongs in a unix/posix programming forum.


    For a 1D array it is easy. Declare ptr as the appropriate type of pointer (e.g. a pointer to char) and then use array syntax as normal until it comes time for your program to release the shared memory.

    Generally, you would not share a multi-dimensional array directly. Instead, map as a 1D array, and transform indices as needed. For a 2D array (with dimensions row and columns) one way of mapping might be....
    Code:
    char some_2D_array[rows][columns];
    
    /*   initialise some_2D_array somehow */
    
    char *ptr = mmap(0, rows*columns,  PROT_WRITE,   MAP_SHARED,  shm_fd, 0);
    for (i = 0; i < rows; ++i)
    {
         for (j = 0; j < columns; ++j)
             ptr[i + rows*j] = some_2D_array[i][j];
    }
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    And just to follow on from Grumpy's solution,

    Code:
    char (*some_2D_array)[columns];
     
    some_2D_array = (char(*)[columns])mmap(0, rows*columns,  PROT_WRITE,   MAP_SHARED,  shm_fd, 0);
    
    // Now you can do some_2D_array[row][col] directly in your shared memory
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Dec 2014
    Posts
    3
    Quote Originally Posted by grumpy View Post
    Note: shared memory is outside scope of the C standard. This really belongs in a unix/posix programming forum.


    For a 1D array it is easy. Declare ptr as the appropriate type of pointer (e.g. a pointer to char) and then use array syntax as normal until it comes time for your program to release the shared memory.

    Generally, you would not share a multi-dimensional array directly. Instead, map as a 1D array, and transform indices as needed. For a 2D array (with dimensions row and columns) one way of mapping might be....
    Code:
    char some_2D_array[rows][columns];
    
    /*   initialise some_2D_array somehow */
    
    char *ptr = mmap(0, rows*columns,  PROT_WRITE,   MAP_SHARED,  shm_fd, 0);
    for (i = 0; i < rows; ++i)
    {
         for (j = 0; j < columns; ++j)
             ptr[i + rows*j] = some_2D_array[i][j];
    }
    Quote Originally Posted by Salem View Post
    And just to follow on from Grumpy's solution,

    Code:
    char (*some_2D_array)[columns];
     
    some_2D_array = (char(*)[columns])mmap(0, rows*columns,  PROT_WRITE,   MAP_SHARED,  shm_fd, 0);
    
    // Now you can do some_2D_array[row][col] directly in your shared memory
    Okay, good stuff. This is all new to me though. How would I edit, read, or otherwise manipulate that data as a one dimensional array? Say I wanted to add a new entry in
    some_2D_array [1][0] or list all the strings in the first column. Sorry if this sounds basic, but I've never heard of treating a multidimensional array as a single array...or vise versa.

    SALEM: Are you saying all I have to do, with your addition to the solution, is treat it directly as a 2D array as I would in a normal program? Because that would be great, and I'll give it a try in the meantime.

    Thanks so far guys.
    Last edited by Louis Sutter; 12-08-2014 at 03:16 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. shared memory array
    By Amanda Watson in forum C Programming
    Replies: 2
    Last Post: 09-25-2012, 12:36 AM
  2. Posix shared memory Q
    By homer_3 in forum C Programming
    Replies: 10
    Last Post: 03-01-2010, 09:13 PM
  3. Posix shared memory
    By rutledmj in forum C Programming
    Replies: 2
    Last Post: 10-04-2009, 09:42 PM
  4. Array of srtuct and shared memory
    By mr.toc in forum C Programming
    Replies: 8
    Last Post: 12-03-2008, 07:45 AM
  5. problem with sending array of struct over shared memory
    By jet-plane in forum C Programming
    Replies: 26
    Last Post: 05-10-2008, 04:10 AM

Tags for this Thread