I want (or need) to do something along the lines of
char **my_array = malloc(1000*64);
strcpy(arr[0], "test");
While I know that arr[0] isn't pointing to a separate piece of allocated memory, I thought one should be able to copy a string into it like this (yet it segs). This works
arr[0] = "test";
However that is not going to work, for my actual goal is to do this in shared memory.
shm_array = shmget(IPC_PRIVATE, 1000 * 64, IPC_CREAT | 0644);
my_array = (char**) shmat(shm_array, (void**)0, 0);
Actually my question could be rephrased to: "How do you create an array of strings in shared memory?". I tried creating 1000 separate "string" shared memory segments, but apart of that it did not work it also seems wrong. Moreover, I thought one should simply be able to write into a big shared memory segment using relative pointer offsets.
You could just create one single piece of memory and write to specific offsets:
char * const buf = malloc(HUGE);
strcpy(buf + offset1, "hello");
strcpy(buf + offset2, "world");
It'd probably be better to use strncpy and pass a size of HUGE - offset along to make sure you don't run over the end. Managing the offsets is your own responsibility. Or you can use strncat, if efficiency doesn't matter so much.
It looks like you are looking for a 2D array 1000 by 64. If this is indeed the case, you can do this:
struct shared_1000_by_64 {
char strings[1000][64];
};
struct shared_1000_by_64 *shared = malloc(sizeof(struct shared_1000_by_64));
for (int i = 0 ; i != 1000 ; i++) {
strcpy(shared->strings[i], "test");
}
This uses the standard trick of preventing the array from decaying into a pointer.
If you want to dynamically allocate an array of 64-character arrays, then use a pointer to an array rather than a pointer to a pointer:
char (*my_array)[64] = malloc(1000 * sizeof my_array[0]);
strcpy(my_array[0], "test");
or for the shared-memory case,
shm_array = shmget(IPC_PRIVATE, 1000 * sizeof my_array[0], IPC_CREAT | 0644);
my_array = shmat(shm_array, NULL, 0);
Related
i am new to coding and am having a problem with the following.
I am required to read from a text file, each row will contain:
command arg1 arg2 arg3...
command arg1 arg2
command
command arg1 arg2 ... arg9
etc
What i am trying to do is read this entire file into a 2D string array called array using malloc. This way if i were to do:
array[0][0] i would access command arg1 arg2 arg3
array[1][0] i would access command arg1 arg2
and so on.
I also know there is a max of 100 rows and 256 characters per line. Below is how i attempted to declare my malloc however when trying to allocate strings to the 2d array, it only allocated single characters.
I dont quite understand how to do this, detailed explanation would be greatly appreciated
int row = 100;
int col = 256;
int **array;
array = (int**)malloc(row*sizeof(array));
if(!array){
perror("Error occured allocating memory");
exit(-1);
}
for(int i = 0; i<row;i++){
array[i] = (int*)malloc(col*sizeof(array));
}
If I got it right, you need to set up a two dimensional array of char * instead of int.
That is, you address the correct row by dereferencing once (array[the_ith_row]), and then address the correct element(command, arg1, arg2, ...) by another dereference (array[the_ith_row][the_jth_col]).
Notice: strings like "arg1" and "command" are treated as "array of chars" therefore you need to store a char * in order to access them. int could only store one char(with some extra space consumption), therefore won't work here.
So, the correct one should look like:
#include <string.h>
int row = 100;
int col = 256;
char ***array;
array = (char ***)malloc(row * sizeof(char **));
if (!array) {
perror("Error occured allocating memory");
exit(-1);
}
for (int i = 0; i < row; i++) {
array[i] = (char **)malloc(col * sizeof(char *));
}
// Do some example assignments
for (int j = 0; j < col; j++) {
array[i][j] = strcpy((char *)malloc(100), "test_string");
}
//therefore printf("%s", array[0][0]); will print test_string"
UPDATE: I missed some * here..
You are allocating using sizeof(array) which is not the correct unit of allocation that you want.
It looks like what you want are two different kinds of memory allocations or objects.
The first is an array of pointers to character strings since the file data is a series of character strings.
The second kind of memory allocation is for the memory to hold the actual character string.
The first kind of memory allocation, to an array of pointers to character strings would be:
char **pArray = malloc (100 * sizeof(char *)); // allocate the array of character string pointers
The second kind of memory allocation, to a character string which is an array of characters would be:
char *pString = malloc ((256 + 1) * sizeof(char)); // allocate a character array for up to 256 characters
The 256 + 1 is needed in order to allocate space for 256 characters plus one more for the end of string character.
So to allocate the entire needed space, you would do the following:
int iIndex;
int nMax = 100;
char **pArray = malloc (nMax, sizeof(char *)); // allocate array of rows
for (iIndex = 0; iIndex < nMax; iIndex++) {
pArray[iIndex] = malloc ((256 + 1) * sizeof (char)); // allocate a row
}
// now use the pArray to read in the lines of text from the file.
// for the first line, pArray[0], second pArray[1], etc.
Using realloc()
A question posed is using the realloc() function to adjust the size of the allocated memory.
For the second kind of memory, memory for the actual character string, the main thing is to use realloc() as normal to expand or shrink the amount of memory. However if memory is reduced, you need to consider if the text string was truncated and a new end of string terminator is provided to ensure the text string is properly terminated with and end of string indicator.
// modify size of a text string memory area for text string in pArray[i]
// memory area. use a temporary and test that realloc() worked before
// changing the pointer value in pArray[] element.
char *p = realloc (pArray[i], (nSize + 1) * sizeof (char));
if (p != NULL) {
pArray[i] = p; // valid realloc() so replace our pointer.
pArray[i][nSize] = 0; // ensure zero terminator for string
}
If you ensure that when the memory area for pArray] is set to NULL after allocating the array, you can just use the realloc() function as above without first using malloc() since if the pointer in the argument to realloc() is NULL then realloc() will just do a malloc() for the memory.
For the first kind of memory, you will need to consider freeing any memory whose pointers may be destroyed when the allocated array is shortened. This means that you will need to do a bit more management and keeping management data about the allocated memory area. If you can guarantee that you will only be increasing the size of the array and never shortening it then you don't need to do any management and you can just use the same approach as provided for the second kind of memory above.
However if the memory allocated for the first kind of memory will need to be smaller as well as larger, you need to have some idea as to the size of the memory area allocated. Probably the easiest would be to have a simple struct that would provide both a pointer to the array allocated as well as the max count of items the array can hold.
typedef struct {
size_t nCount;
char **pArray;
} ArrayObj;
Warning: the following code has not been tested or even compiled. Also note that this only works for if the memory allocation will be increased.
Then you would wrap the realloc() function within a management function. This version of the function only handles if realloc() is always to expand the array. If making it smaller you will need to handle that case in this function.
ArrayObj ArrayObjRealloc (ArrayObj obj, size_t nNewCount)
{
// make the management a bit easier by just adding one to the count
// to determine how much memory to allocate.
char **pNew = realloc (obj.pArray, (nNewCount + 1) * sizeof (char *));
if (pNew != NULL) {
size_t ix;
// realloc() worked and provided a valid pointer to the new area.
// update the management information we are going to return.
// set the new space to NULL to have it in an initial and known state.
// initializing the new space to NULL will allow for knowing which array
// elements have a valid pointer and which don't.
obj.pArray = pNew;
for (ix = nNewCount; ix >= obj.nCount; ix--) {
obj.pArray[ix] = NULL;
}
obj.nCount = nNewCount;
}
return obj;
}
and use this function something like
AnyObj obj = {0, NULL};
// allocate for the first time
obj = ArrayObjRealloc (obj, 100);
// do stuff with the array allocated
strcpy (obj.pArray[i], "some text");
// make the array larger
obj = ArrayObjRealloc (obj, 150);
This question already has answers here:
C - shared memory - dynamic array inside shared struct
(5 answers)
Closed 5 years ago.
I am working on a server with forking which stores a map(k->v) of strings in shared memory. I want to do it very simplistic but am lost in pointers and in what exactly I need to copy. So I extracted the relevant code which looks like this:
struct key_value {
char key[32];
char value[32];
};
struct key_value **map;
int *map_size;
int shmid = shmget(IPC_PRIVATE, sizeof(struct key_value**), 0600);
map = (struct key_value**) shmat(shmid, 0, 0);
int shmid_size = shmget(IPC_PRIVATE, sizeof(int), 0600);
map_size = (int*) shmat(shmid_size, 0, 0);
*map_size = 0;
//the above happens before fork()
char *c = "abc";
int shmid_struct = shmget(IPC_PRIVATE, sizeof(struct key_value*), 0600);
struct key_value *entry = (struct key_value*) shmat(shmid_struct, 0, 0);
*entry->key = *c;
printf("%s\n", map[0]->key);
//smhdt's & shmctl's
So what I want is to copy that string "abc" from *c into the map so into shared memory. Clearly, I do not yet fully understand pointers and structs so am hoping someone can clear it up. I currently get a segfault 'somewhere in main' (thanks gdb...).
Note that I am ok with the map having a fixed max_size for now (though would be great if dynamic).
EDIT: it's been pointed out in an answer that having a char* in the struct is difficult, so to use char[x] instead. Have updated the code to reflect that, but still not working.
Structures which contain pointers cannot be safely stored in shared memory, as the pointers are meaningless outside the process that created them. Even if the shared memory region is mapped at the same address in each process (which is true if the memory was mapped before a fork(), but may be false in other scenarios), pointers into non-shared memory will not behave properly, as each process may have different data at that address.
If you want to store strings in shared memory, you will need to store them as explicit character arrays, e.g.
struct key_value {
char key[32];
char value[32];
};
or use another scheme, such as storing an offset into a string table in the shared memory region.
Generally speaking, though, shared memory is not a good tool for inter-process communication. If your application depends on being able to share data in memory, threading is probably a better approach.
Hello I am experiencing something I really don't understand the principle with structures in C.
One of my structures contains 2 character strings (named 'seq' and 'foldedSeq'). Both these strings (should) have the same dimensions.
However when I try to modify one, the second automatically takes the same modifications at the same specified place of the string.
Here is the interesting chunk of code:
typedef struct MD {
int nb_line;
int nb_colomn;
EM ** matrix;
char * seq; // Initial sequence.
char * foldedSeq;
} MD;
void set_sequences(MD * M, char * seq) {
M->seq = seq;
M->foldedSeq = M->seq; //Purpose: give to foldedSeq the seq dimensions (perhaps it is useless).
printf("seq= %s\tstrlen= %d\nM->seq= %s\nM->foldedSeq= %s\n", seq, strlen(seq), M->seq, M->foldedSeq);
// Up to this point 'seq' = 'foldedSeq'
int i;
for( i = 0; i < strlen(seq); i++) {
M->foldedSeq[i] = '-'; // Original purpose: make 'foldedSeq' string filled with hyphens only.
}
printf("seq= %s\tstrlen= %d\nM->seq= %s\nM->foldedSeq= %s\n", seq, strlen(seq), M->seq, M->foldedSeq);
// Here is the problem: the string 'seq' REALLY IS modified alongside with 'foldedSeq'... WHY? :(
}
Since I wrote "M->foldedSeq[i]" should be modified, why would "M->seq[i]" be modified as well ??
Thank you for reading and providing me explanations, my logic found a dead end here.
M->seq = seq;
M->foldedSeq = M->seq;
is the same as saying
M->seq = seq;
M->foldedSeq = seq;
They are both pointing to the same location in memory. So modifying one is modifying both.
Probably what you want to do instead is malloc a block of memory that is the same length as the other.
M->foldedSeq = calloc(strlen(seq) + 1, sizeof(char));
What you're witnessing is simple pointer aliasing, a basic feature of the C language. Because you explicitly assign both seq and foldedSeq members to point to the same bit of memory, and modifications through one pointer will be witnessed by the other. If that's not what you intended/wanted, you'd need to copy the memory block of seq before assigning it to foldedSeq to keep the two distinct.
Because they both point to the same memory address and when you modify one you are modifying the other.
This assignment: M->foldedSeq = M->seq; is just assigning memory locations, not doing any sort of copy.
If you want to keep them separate, you will have to allocate memory and copy the string into the new memory.
Try either:
M->foldedSeq = strdp(M->seq) if you want to copy the content too.
Or:
M->foldedSeq = malloc(strlen(M->seq) + 1); to just have a new memory space of the same size.
This line:
M->foldedSeq = M->seq;
is setting the foldedSeq pointer to the same value as seq. It is not creating new space and copying the contents of seq to foldedSeq which is maybe where the confusion is. So when you modify either one the other will be modified as well. One possible solution is to use strdup:
M->foldedSeq = strdup( M->seq ) ;
I have an array, say, text, that contains strings read in by another function. The length of the strings is unknown and the amount of them is unknown as well. How should I try to allocate memory to an array of strings (and not to the strings themselves, which already exist as separate arrays)?
What I have set up right now seems to read the strings just fine, and seems to do the post-processing I want done correctly (I tried this with a static array). However, when I try to printf the elements of text, I get a segmentation fault. To be more precise, I get a segmentation fault when I try to print out specific elements of text, such as text[3] or text[5]. I assume this means that I'm allocating memory to text incorrectly and all the strings read are not saved to text correctly?
So far I've tried different approaches, such as allocating a set amount of some size_t=k , k*sizeof(char) at first, and then reallocating more memory (with realloc k*sizeof(char)) if cnt == (k-2), where cnt is the index of **text.
I tried to search for this, but the only similar problem I found was with a set amount of strings of unknown length.
I'd like to figure out as much as I can on my own, and didn't post the actual code because of that. However, if none of this makes any sense, I'll post it.
EDIT: Here's the code
int main(void){
char **text;
size_t k=100;
size_t cnt=1;
int ch;
size_t lng;
text=malloc(k*sizeof(char));
printf("Input:\n");
while(1) {
ch = getchar();
if (ch == EOF) {
text[cnt++]='\0';
break;
}
if (cnt == k - 2) {
k *= 2;
text = realloc(text, (k * sizeof(char))); /* I guess at least this is incorrect?*/
}
text[cnt]=readInput(ch); /* read(ch) just reads the line*/
lng=strlen(text[cnt]);
printf("%d,%d\n",lng,cnt);
cnt++;
}
text=realloc(text,cnt*sizeof(char));
print(text); /*prints all the lines*/
return 0;
}
The short answer is you can't directly allocate the memory unless you know how much to allocate.
However, there are various ways of determining how much you need to allocate.
There are two aspects to this. One is knowing how many strings you need to handle. There must be some defined way of knowing; either you're given a count, or there some specific pointer value (usually NULL) that tells you when you've reached the end.
To allocate the array of pointers to pointers, it is probably simplest to count the number of necessary pointers, and then allocate the space. Assuming a null terminated list:
size_t i;
for (i = 0; list[i] != NULL; i++)
;
char **space = malloc(i * sizeof(*space));
...error check allocation...
For each string, you can use strdup(); you assume that the strings are well-formed and hence null terminated. Or you can write your own analogue of strdup().
for (i = 0; list[i] != NULL; i++)
{
space[i] = strdup(list[i]);
...error check allocation...
}
An alternative approach scans the list of pointers once, but uses malloc() and realloc() multiple times. This is probably slower overall.
If you can't reliably tell when the list of strings ends or when the strings themselves end, you are hosed. Completely and utterly hosed.
C don't have strings. It just has pointers to (conventionally null-terminated) sequence of characters, and call them strings.
So just allocate first an array of pointers:
size_t nbelem= 10; /// number of elements
char **arr = calloc(nbelem, sizeof(char*));
You really want calloc because you really want that array to be cleared, so each pointer there is NULL. Of course, you test that calloc succeeded:
if (!arr) perror("calloc failed"), exit(EXIT_FAILURE);
At last, you fill some of the elements of the array:
arr[0] = "hello";
arr[1] = strdup("world");
(Don't forget to free the result of strdup and the result of calloc).
You could grow your array with realloc (but I don't advise doing that, because when realloc fails you could have lost your data). You could simply grow it by allocating a bigger copy, copy it inside, and redefine the pointer, e.g.
{ size_t newnbelem = 3*nbelem/2+10;
char**oldarr = arr;
char**newarr = calloc(newnbelem, sizeof(char*));
if (!newarr) perror("bigger calloc"), exit(EXIT_FAILURE);
memcpy (newarr, oldarr, sizeof(char*)*nbelem);
free (oldarr);
arr = newarr;
}
Don't forget to compile with gcc -Wall -g on Linux (improve your code till no warnings are given), and learn how to use the gdb debugger and the valgrind memory leak detector.
In c you can not allocate an array of string directly. You should stick with pointer to char array to use it as array of string. So use
char* strarr[length];
And to mentain the array of characters
You may take the approach somewhat like this:
Allocate a block of memory through a call to malloc()
Keep track of the size of input
When ever you need a increament in buffer size call realloc(ptr,size)
After a quick scan of related questions on SO, I have deduced that there's no function that would check the amount of memory that malloc has allocated to a pointer. I'm trying to replicate some of std::string basic functionality (mainly dynamic size) using simple char*'s in C and don't want to call realloc all the time. I guess I'll need to keep track of how much memory has been allocated. In order to do that, I'm considering creating a typedef that will contain the string itself and an integer with the amount of memory currently allocated, something like this:
typedef struct {
char * str;
int mem;
} my_string_t;
Is that an optimal solution, or perhaps you can suggest something that will bear better results? Thanks in advance for your help.
You will want to allocate the space for both the length and the string in the same block of memory. This may be what you intended with your struct, but you have reserved space for only a pointer to the string.
There must be space allocated to contain the characters of the string.
For example:
typedef struct
{
int num_chars;
char string[];
} my_string_t;
my_string_t * alloc_my_string(char *src)
{
my_string_t * p = NULL;
int N_chars = strlen(src) + 1;
p = malloc( N_chars + sizeof(my_string_t));
if (p)
{
p->num_chars = N_chars;
strcpy(p->string, src);
}
return p;
}
In my example, to access the pointer to your string, you address the string member of the my_string_t:
my_string_t * p = alloc_my_string("hello free store.");
printf("String of %d bytes is '%s'\n", p->num_chars, p->string);
Be careful to realize that you are obtaining the pointer for the string as a consequence of allocating space to store the characters. The resource you are allocating is the storage for the characters, the pointer obtained is a reference to the allocated storage.
In my example, the memory allocated is laid out sequentially as follows:
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 00 | 00 | 11 | 'h'| 'e'| 'l'| 'l'| 'o'| 20 | 'f'| 'r'| 'e'| 'e'| 20 | 's'| 't'| 'o'| 'r'| 'e'| '.'| 00 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
^^ ^
|| |
p| |
p->num_chars p->string
Notice that the value of p->string is not stored in the allocated memory, it is four bytes from the beginning of the allocated memory, immediately subsequent to the (presumed 32-bit, four-byte) integer.
Your compiler may require that you declare the flexible C array as:
typedef struct
{
int num_chars;
char string[0];
} my_string_t;
but the version lacking the zero is supposedly C99-compliant.
You can accomplish the equivalent thing with no array member as follows:
typedef struct
{
int num_chars;
} mystr2;
char * str_of_mystr2(mystr2 * ms)
{
return (char *)(ms + 1);
}
mystr2 * alloc_mystr2(char *src)
{
mystr2* p = NULL;
size_t N_chars = strlen(src) + 1;
if (N_chars num_chars = (int)N_chars;
strcpy(str_of_mystr2(p), src);
}
return p;
}
printf("String of %d bytes is '%s'\n", p->num_chars, str_of_mystr2 (p));
In this second example, the value equivalent to p->string is calculated by str_of_mystr2(). It will have approximately the same value as the first example, depending on how the end of structs are packed by your compiler settings.
While some would suggest tracking the length in a size_t I would look up some old Dr. Dobb's article on why I disagree. Supporting values greater than INT_MAX is of doubtful value to your program's correctness. By using an int, you can write assert(p->num_chars >= 0); and have that test something. With an unsigned, you would write the equivalent test something like assert(p->num_chars < UINT_MAX / 2); As long as you write code which contains checks on run-time data, using a signed type can be useful.
On the other hand, if you are writing a library which handles strings in excess of UINT_MAX / 2 characters, I salute you.
This is the obvious solution. And while you are at it, you might want to have a struct member that maintains the amount of allocated memory actually in use. This will avoid having to call strlen() all the time, and would enable you to support non null-terminated strings, as the C++ std::string class does.
That is how it was done in the Pleistocene, and that's how you should do it today. You are dead on the money that malloc does not offer any portable, supported, mechanism to query the size of an allocated block.
A more common way is to wrap malloc (and realloc) and keep a list of sizes and pointers
That way you don't need to change any string functions.
write wrapper functions. If you are using malloc then you should do that anyway.
For an example look in "writing solid code"
I think you could use malloc_usable_size.