0

My task is to create shared memory by using a program. It writes string from command line argument to shared memory section. It will be then read by another program. I'm using structure to create shared memory. Now, my questions is I’m not able to pass strings which were given in command line into structure variable. How can I write multiple strings into one array of pointers of char variable?

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <malloc.h>
#include "shm-com.h"

void main(int argc,char *argv[])
{
 key_t shmKey;
 int shm_id,i,j=0;
 struct memory *dataptr;
 char *string[10];

 shmKey = ftok(".",1234);
 printf("no. of strings %d\n",argc);

 shm_id  = shmget(shmKey,sizeof(struct memory),0666 | IPC_CREAT);

 if(shm_id < 0)
 {
  perror("shm_id didn't create\n");
  exit(0);
 }

 dataptr = (struct memory *)shmat(shm_id,NULL,0);
 if((int) dataptr == -1)
 {
  perror("****didn't attatch to share memory\n");
 }

 printf("share memory attatched at %p address\n",dataptr);

 dataptr->status = NOT_READY;
 for(i = 1;i < argc;i++)
 {
 string[j] = argv[i];
 j++;
 }
 printf("data attached to share memory\n");

 for(i = 0;i < argc ; i++)
 {
 printf("%s\n",string[i]);
 }

 for(i = 0;i < argc;i++)
 {
 strcpy(dataptr->data[i],argv[i]);

 }

 dataptr->status = FILLED;

 printf("please start client window\n");

 while(dataptr != TAKEN);
 sleep(1);

 shmdt((void *)dataptr);
 printf("server has detached sharre memory\n");

 shmctl(shm_id,IPC_RMID,NULL);

 printf("server cancelled shared memroy\n");
 exit(0);
 }

and my structure file name shm-com.h is

#define TAKEN 1
#define FILLED 0
#define NOT_READY -1

struct memory
{
 char *data[10];
 int status;
};
1
  • you probably wat to use some sort of shared semaphore or spinlock instead of the simple "int status" it helps avoid race conditions and can be more efficint than inspect-sleep loops. Commented Jan 3, 2015 at 20:22

2 Answers 2

1

you will have to copy the stings into a buffer in the shared memory, and because the shared memory may have a different base address on each process you will have to reference them by offset into the buffer instead of by pointer.

you will also then have to maintain a used/free map in the buffer so you know which parts are free and which are used.

shared memory is good for broadcasting data, but between only two processes it's usually easier to use some sort of socket, (unix or inet) or pipe (anonymous or named).

Sign up to request clarification or add additional context in comments.

Comments

0

Main problem is the fact that your struct contains only string pointers, not the actual string content (which is still located in memory that belongs to the original process, not in shared memory).

The simplest solution is to use a 2-dimensional character array.

struct memory
{
    char data[10][100];
    int status;
};

You already use strcpy to copy your data to the struct, so it will work without too many code changes. Though I do strongly advice you to replace strcpy by something that is not prone to buffer overflow.

Disadvantage: if string length varies, then your struct may contain a lot of unused space, due to the fixed size of the array. An alternative would be to use a single one-dimensional character array and simply concatenate the ten strings, using \0 as a separator.

Partial code (just the changes):

struct memory
{
    int status;
    char data[1];     /* data MUST be last in the struct! */
};

int size = sizeof(struct memory) - 1;   /* subtract one because [1] will be overruled */
for (i = 1; i < argc; i++)
{
    size += strlen(argv[i]) + 1;        /* adding one to hold '\0' */
}

shm_id  = shmget(shmKey, size, 0666 | IPC_CREAT);   /* I adjusted the size parameter here */

int offset = 0;
for (i = 1; i < argc; i++)
{
    strcpy(dataptr->data + offset, argv[i]);
    offset += strlen(argv[i]) + 1;
}

Of course, you will have to make a similar change at the receiving end; split the data at every '\0' character.


A bit off-topic, this code is wrong:

while(dataptr != TAKEN);
sleep(1);

First of all, you are comparing a pointer with an integer (please enable compiler warnings). As it is now, it is an infinite loop. And even if it wasn't, it is a CPU-intensive busy-waiting loop. If sleep(1); was supposed to be part of the loop (which would certainly give the CPU some rest), then you should remove the semicolon at the end of the while statement.

I guess you wanted to do this:

while (dataptr->status != TAKEN)
    sleep(1);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.