Initialize 2-D array of unknown size - c

I have a 2-D array of characters e.g. char aList[numStrings][maxLength]. ideally, during program execution I want to be able to modify the contents of aList i.e. add, amend or delete entries. Since aList will be subject to change, I don't want to have to recompile my program after every such change to modify aList. So I want to write aList out to a text file at program end and then read it back into aList at the commencement of the next program run.
However, I don't know at program start what is the value of numStrings. (I am not using C99 so I can't use a VLA, and pick up a count of previous strings from an external file.) I could, of course, set numStrings to an artificially high value but that grates!
Is there a way to populate aList without knowing the value of numStrings? I don't think there is (I have looked at related questions) but is there another way of achieving what I need?

If you really want to be able to remove items from the middle of the grid (your questions isn't clear on this), you'll need some kind of multiply linked structure. These are often used to implement sparse arrays, so you can probably find one pre-made.
I'm talking about something like this:
+---+
| A |
+-|\+
| \
| \
| \
| \
| +----+----+----+
| | C0 | C1 | C2 | ...
| +--|-+----+--|-+
| | |
| | |
+-V--+ +--V-+ | +----+
| R0 |->|a0,0|-------+>|a0,3|--> ...
+----+ +--|-+ +--V-+----+
| R1 |-----+----->|a1,2|--> ...
+----+ | +--|-+
... V |
... V
...
Where A is the root node of the object, C is an array of column pointers, R is an array of row pointers, and each cell points to it next neighbor along both its row and column. All cells not explicitly represented are assumed to have some default value (usually NULL or 0).
It is a simple idea, but a fairly picky implementation, with lots of chances to mess up, so use a debugged library if you can.

You could use a dynamically allocated array. Use malloc() to make one, realloc() to change the size of one, and free() when you're done with it. But this has already been covered by another answer.
Another alternative is to use a linked list. That way you don't have to realloc() every time you want to extend your array - realloc() can be rather expensive if it has to copy the entire array to a new location.

The situation you've described is precisely what malloc is for -- allocating a variable-length block of memory.

If your plan is to populate while reading in the file you could do one of two things.
Either store the number of strings as the first element in the file, then the suggestion by jgottula would work well.
Or, must you use an array? You could read them directly into a linked list, and then when finished reading, move them into an array, and free up the linked list.

2D C-style arrays in general are, sorry the term, kindof wacky ... they look simple and useful on paper but implementing dynamic memory management - handling of allocation failures and cleanups/resizes - is often quite difficult in detail.
What you can do is something like:
/*
* Start with an array that can hold INITIAL_NUM elements of (char*).
*/
char **aList = (char**)malloc(INITIAL_NUM, sizeof(*aList));
int curIdx = 0, curListSz = INITIAL_NUM;
while (more_stuff_to_append) {
/*
* Still space in the existing list ? If not - resize
*/
if (curIdx >= INITIAL_NUM) {
curListSz += ALLOC_INCREMENT_FOR_ALIST;
if ((aList = realloc(aList, curListSz * sizeof(*aList))) == NULL)
error_and_yucky_cleanup("can't resize list, out of memory");
}
/*
* Allocate a new element.
* Note that if it's _known_ in advance that all elements
* are the same size, then malloc'ing a big block and slicing
* that into pieces is more efficient.
*/
if ((aList[curIdx] = malloc(new_elem_size, sizeof(char)) == NULL)
error_and_yucky_cleanup("out of memory");
/*
* put the contents into the new buffer, however that's done.
*/
populate_new_entry(aList[curIdx]);
curIdx++;
}
The big problem with these approaches is usually that cleanup is messy. One needs to go through the array and call free() on every element, plus the additional final one to clean up aList itself.
If you know all sizes in advance, one can allocate a single memory block that holds both aList and all the elements. This works via something like:
#define LISTSZ(lst) (NUMSTRINGS_MAX * sizeof(*(lst)))
#define ELEMSZ(lst) (STRINGSIZE_MAX * sizeof(**(lst)))
char **aList = malloc(LISTSZ(aList) + NUMSTRINGS * ELEMSZ(aList));
char *curElem = ((char*)aList) + LISTSZ(aList));
int i;
for (i = 0; i < NUMSTRINGS_MAX; i++) {
aList[i] = curElem;
curElem += ELEMSZ(aList);
}
The advantage of this is that cleanup is trivial - just call free((char*)aList); and the whole thing is gone. But you can't realloc() it anymore as that wouldn't insert new space at the beginning of the memory block (where aList[] is stored).
These things make up really good reasons for using C++ vectors; at least C++ does the cleanup (e.g. on out of memory exceptions) automatically.

You can dynamically allocate the array:
char **aList;
int i;
aList = malloc(sizeof(char *) * numStrings);
for (i = 0; i < numStrings; i++)
{
aList[i] = malloc(maxLength);
}
If, by any chance, you can use C++ instead of C, you could always use a C++ vector:
std::vector<std::vector<char> > aList;

Related

How is memory allocated to multi-nested structs in C?

A couple of days ago, I asked this question. I duplicated 90% of the code given in the answer to my previous question. However, when I used Valgrind to do memcheck, it told me that there were memory leaks. But I don't think it was that 10% difference that caused the memory leaks. In addition to the memory leak issue, I have a couple of other questions.
A brief summary of my previous post:
I have a multi-nested struct. I need to correctly allocate memory to it and free the memory later on. The structure of the entire struct should look like this:
College Sys
| | | ... |
ColleA ColleB ColleC ... ColleX
| | | | | | | | | | | | ... | | | |
sA sB sC sD sA sB sC sD sA sB sC sD ... sA sB sC sD
| | | | | | | | | | | | ... | | | |
fam fam ...
// Colle is short for college
// s is short for stu (which is short for student)
There could be arbitrary number of colleges and students, which is controllable by #define MAX_NUM _num_.
As per the previous answer, I should allocate memory in the order of "outermost to innermost" and free the memory "innermost to outermost". I basically understand the logic behind the pattern. The following questions are extensions to it.
1) Does
CollegeSys -> Colle = malloc(sizeof(*(CollegeSys -> Colle)) * MAX_NUM);
CollegeSys -> Colle -> stu = malloc(sizeof(*(CollegeSys -> Colle -> stu)) * MAX_NUM);
CollegeSys -> Colle -> stu -> fam = malloc(sizeof(*(CollegeSys -> Colle -> stu -> fam)));
mean " there are MAX_NUM colleges under the college system, each of which has MAX_NUM students — each of which has one family"?
1.a)If yes, do I still need for loops to initialize every single value contained in this huge struct?
For example, the possibly correct way:
for (int i = 0; i < MAX_NUM; i++) {
strcpy(CollegeSys -> Colle[i].name, "collestr");
for (int n = 0; n < MAX_NUM; n++) {
strcpy(system -> Colle[i].stu[n].name, "stustr");
...
}
}
the possibly incorrect way:
strcpy(CollegeSys -> Colle -> name, "collestr");
strcpy(CollegeSys -> Colle -> stu -> name, "stustr");
I tried the "possibly incorrect way". There was no syntax error, but it would only initialize CollegeSys -> Colle[0].name and ... -> stu[0].name. So, the second approach is very likely to be incorrect if I want to initialize every single attribute.
2) If I modularize this whole process, separating the process into several functions that return corresponding struct pointers — newSystem(void), newCollege(void), newStudent(void) (arguments might not necessarily be void; we might also pass a str as the name to the functions; besides, there might be a series of addStu(), etc... to assign those returned pointers to the corresponding part of CollegeSys). When I create a new CollegeSys in newSystem(), is it correct to malloc memory to every nested struct once and for all within newSystem()?
2.a) If I allocate memory to all parts of the struct in newSystem(), the possible consequence I can think of so far is there would be memory leaks. Since we've allocated memory to all parts when creating the system, we inevitably have to create a new struct pointer and allocate adequate memory to it in the other two functions too. For instance,
struct Student* newStudent(void) {
struct Student* newStu = malloc(sizeof(struct Student));
newStu -> fam = malloc(sizeof(*(newStu -> fam)));
// I'm not sure if I'm supposed to also allocate memoty to fam struct
...
return newStu;
}
If so, we actually allocate the same amount of memory to an instance at least twice — one in the newSystem(void), the other in newStudent(void). If I'm correct so far, this is definitely memory leak. And the memory we allocate to the pointer newStu in newStudent(void) can never be freed (I think so). Then, what is the correct way to allocate memory to the whole structure when we separate the whole memory allocation process into several small steps?
3) Do we have to use sizeof(*(layer1 -> layer2 -> ...)) when malloc'ing memory to a struct nested in a struct? Can we directly specify the type of it? For example, doing this
CollegeSys -> Colle = malloc(sizeof(struct College) * MAX_NUM);
// instead of
// CollegeSys -> Colle = malloc(sizeof(*(CollegeSys -> Colle)) * MAX_NUM);
4) It seems even if we allocate a certain amount of memory to a pointer, we still can't prevent segfault. For example, we code
// this is not completely correct C code, just to show what I mean
struct* ptr = malloc(sizeof(struct type) * 3);
We still could call ptr[3], ptr[4] and so on, and the compiler will print out nonsense. Sometimes, the compiler may throw an error but sometimes may not. So, essentially, we can't rely on malloc (or calloc and so forth) to avoid the appearance of segfault?
I'm sorry about writing such a long text. Thanks for your patience.

How to deallocate a pointer to pointer, such that all the elements within are freed too?

I am working on a hashtable data structure, and I've come across a problem with a memory leak. Basically I have this code:
int main(int argc, char const *argv[])
{
// -----------------------------+
// record 0 |
// -----------------------------+
rec_t *r = malloc(sizeof(rec_t));
r->key = "name";
r->value = "evgeny";
// -----------------------------+
// -----------------------------+
// record 1 |
// -----------------------------+
rec_t *r2 = malloc(sizeof(rec_t));
r2->key = "lastName";
r2->value = "Danilenko";
// -----------------------------+
// -------------------------------+
// dictionary struct |
// params : uint length |
// rec_t **records |
// -------------------------------+
dct_t* dict = malloc(sizeof(dct_t));
dict->records = malloc(sizeof(rec_t*) * 20);
dict->records[0] = r;
dict->records[1] = r2;
// free(dict->records[0]); // DONT WANT TO DO THIS! O(n)
// free(dict->records[1]);
free(*dict->records); // clears only 1st element cuz pointer
free(dict->records);
free(dict);
return 0;
}
How would I got about free()'ing all of the elements with 'one shot'? I had a look a this link but it didn't help - How to free a struct that contains only pointers
I want to emphasise that I don't want to loop through all the elements and freeing the one-by-one.
I don't want to loop through all the elements and freeing the one-by-one.
Too bad.
If you allocated them with separate calls to malloc, you have to free them with separate calls to free.
The alternative is to use something like apr_pool_t from LibAPR, which is a pool allocator which lets you free the entire pool at once. But this is a rather drastic solution to a simple, ordinary problem.
Short answer:
There's no default way of one-shot approach, you have to call free() on all the pointers returned by memory allocator function (whether you like it or not.)
Elaborate:
You can , however, alter the data structure to include a member to hold the number of allocation calls, and use the value to allocate (and deallocate) the memory, in a loop. Something like
dict->numRecords = n;
// allocate, use, something else......
for (int i = 0; i < dict->numRecords; i++)
free (dict->(records[i]) );
Point to note, you are freeing the elements one-by-one in the later approach, too, we're just making the code concise using the loop.

how do i delete arrays of typedef structs?

I am trying to delete an array of initialized structs e.g. reset the array
My struct:
struct entry{
char name[NAME_SIZE];
int mark;
};
typedef struct entry Acct;
Acct dism2A03[MAX_ENTRY];
Acct clear[0]; << temp struct to set original struct to null
My attempt:
entry_total keeps track of how many structs in the struct array dism2A03[x] have values set in them.
I tried to create an empty array of the same struct clear[0]. Looped through initialized arrays in dism2A03[x] and set them to clear[0]
for(m=0;m<entry_total;m++){
dism2A03[m]=clear[0];
}
break;
However, it is setting them to 0, i want them to become uninitialized e.g. no values in them
You cannot have memory with no value in it. It's physically impossible. It's due to the laws of physics of our universe :-)
Also, this:
Acct clear[0];
is wrong. You cannot have an array with zero elements. Some compilers will allow this as an extension, but it's not valid C. And for the compilers that allow this, it doesn't do what you think it does.
It would seem to me that what you want instead is to resize the array. To do that, you would need to copy the elements you want to keep into a new array, and then free() the old one. To do that, you need to create dism2A03 using dynamic memory:
Acct *dism2A03 = malloc(sizeof(Acct) * MAX_ENTRY);
if (dism2A03 == NULL) {
// Error: We're out of memory.
}
(malloc() returns NULL if there's no more free memory, and the code checks that. Usually all you can do if this happens is terminate the program.)
When you want a new array with some elements removed, then you should back up the starting address of the current one:
Acct* oldArray = dism2A03;
then create a new one with the new size you want:
dism2A03 = malloc(sizeof(Acct) * NEW_SIZE);
if (dism2A03 == NULL) {
// Error: We're out of memory.
}
copy the elements you want from the old array (oldArray) to the new one (dism2A03) - which is up to you, I don't know which ones you want to keep - and after than you must free the old array:
free(oldArray);
As a final note, you might actually not want to create a new array at all. Instead, you could keep having your original, statically allocated array ("statically allocated" means you're not using malloc()):
Acct dism2A03[MAX_ENTRY];
and have a index variable where you keep track of how many useful elements are actually in that array. At first, there are 0:
size_t dism2A03_size = 0;
As you add elements to that array, you do that at the position given by dism2A03_size:
dism2A03[dism2A03_size] = <something>
++dism2A03_size; // Now there's one more in there, so remember that.
While doing so, you need to make sure that dism2A03_size does not grow larger than the maximum capacity of the array, which is MAX_ENTRY in your case. So the above would become:
if (dism2A03_size < MAX_SIZE) {
dism2A03[dism2A03_size] = <something>
++dism2A03_size; // Now there's one more in there, so remember that.
} else {
// Error: the array is full.
}
As you can see, adding something to the end of the array is rather easy. Removing something from the end of the array is just as easy; you just decrement dism2A03_size by one. However, "removing" something from the middle of the array means copying all following elements by one position to the left:
for (size_t i = elem_to_remove + 1; i < dism2A03_size; ++i) {
dism2A03[i - 1] = dism2A03[i];
}
--dism2A03_size; // Remember the new size, since we removed one.
Note that you should not attempt to remove an element if the array is empty (meaning when dism2A03_size == 0.)
There's also the case of adding a new elements in the middle of the array rather than at the end. But I hope that now you can figure that out on your own, since it basically a reversed version of the element removal case.
Also note that instead of copying elements manually one by one in a for loop, you can use the memcpy() function instead, which will do the copying faster. But I went with the loop here so that the logic of it all is more obvious (hopefully.)
when you declare an array in this way Acct dism2A03[MAX_ENTRY]; the array is allocated in the stack, therefore it will be removed when the function will perform the return statement.
What you can do is to allocate the structure in the heap via malloc/calloc, and then you can free that memory area via the free function.
For example :
typedef struct entry Acct;
Acct * dism2A03 = calloc(MAX_ENTRY, sizeof( struct entry));
// ....
free(dism2A03);

How to _delete_ element from dynamic array?

I have seen other answers to questions like this, but none seemed to work for me. Say I have a dynamic array:
int* myarray;
myarray = malloc(myarray, 4*sizeof(int));
myarray[0] = 1;
myarray[1] = 2;
myarray[2] = 3;
myarray[3] = 4;
What I want to do is to remove (and free, because the array will keep on getting larger and larger) the first element of the array. I am well aware of realloc which removes the last element of the array if shrunk. Any ideas on this? Is this possible?
Thanks in advance!
One method I can think of is doing
memmove(myarray, myarray+1, 3*sizeof(int))
and then use realloc to shrink the array. I'm not sure there are more efficient ways to do this in C.
You have to shunt all the other elements along one. Conceptually, it's like this:
for( int i = 0; i < 3; i++ ) p[i] = p[i+1];
As others have mentioned, memmove is optimized for shifting memory segments that overlap, rather than using the above loop.
Moving data around is still inefficient as your array grows larger. Reallocating an array every time you add an item is even worse. General advice is don't do it. Just keep track of how large your array is and how many items are currently stored in it. When you grow it, grow it by a significant amount (typically you would double the size).
It sounds like you might want a circular queue, where you preallocate the array, and a head and tail pointer chase each other round and round as you push and pop items on.
Typically a "Delete" operation is not possible on an array. Perhaps you want to create and use a linked list?
C++ has its std::vector which supports this. What it would do is to shift elements that come later, forward by 1 element. You could implement this, and call realloc later.
Storing them in reverse is an obvious workaround if only first element needs to be deleted.
I don't think that you'll find a proper/clean way to do that in C. C++ as some lybraries who do that, and almost all the OO oriented languages can do that, but not C. All I can think of is moving memory and, yes, calling realloc, or setting the position you want to free to a known value wich you'll consider empty in a memory re-use policy.
Another way to turn the problem is by a dynamic implementation of the array. DOn't know if you want to go there, but if you do, here's some brief example.
Since you're only saving integers, a struct like this:
typedef struct DynamicArray_st{
int x;
struct DynamicArray_st *next;
}DynamicArray;
Makes it possible to alloc and free elements as the program needs to. It also allows insertion in the middle, begin or end and the same for frees.
The way you'll do it is by saving a pointer to the begin of this dynamic type and then iterate over it.
The problem is that you can't access data by the [] notation. Iterations are necessary wich makes it heavier on processing time.
Besides that, your code would become something like this:
DynamicArray *array = malloc(sizeof(DynamicArray)); /*Just a first element that will stay empty so your Dynamic array persists*/
array->next = NULL;
DynamicArray *aux = array;
DynamicArray *new;
for(i = 0; i<4; i++){
new = malloc(sizeof(DynamicArray));
new->next = NULL;
new->x = i+1;
aux->next = new;
aux = new;
}
Here you have a sequence of structs in a way that each struct points to the next one and has a integer inside.
If now you'd do something like:
aux = array->next; /*array points to that empty one, must be the next*/
while(aux != NULL){
printf("%d\n",aux->x);
aux = aux->next;
}
You'll get the output:
1
2
3
4
And freeing the first element is as easy as:
aux = array->next;
array->next = aux->next;
free(aux);
If you try to draw it(structs are boxes and next/aux/next are arrows) you'll see one boxe's arrow outline an box - the one you want to free.
Hope this helps.

I need to make a global array in C with a size inputted by the user

Basically I need to make a global variable in C that is an array. The Array will be [n][22][n+1] where n is either 3,4,5 or 6 and is selected by the user.
Is there a way to do this or should I just make the array [6][22][7], and have the functions dealing with it only use the parts up to n (if that makes any sense)?
I've had to do this before for a computer science class but can't remember exactly how to do it.
For an array that small (well, assuming reasonably sized data types), you might just be better off making the [6][22][7] allocation you mention in your question - it's not like you're going to waste that much space. Unfortunately for you, C99 variable length arrays don't work for global arrays. That means your only other option is dynamic allocation using malloc()/free().
You can use a file scope pointer that points to the first element of an array you dynamically allocate (malloc function) in a function.
As was mentioned previously, in this particular case, doing anything else than a static assignment of [6][22][7] would be a waste of time. If you really want to dynamically allocate the array using malloc :
/* Suppose that you want a [5][22][6] */
int main() {
int i,j,k;
int ***boo;
int d_1,d_2,d_3;
d_1=5;
d_2=22;
d_3=6;
/*
+------------------------------------------+
| For each dimension, a malloc is needed |
+------------------------------------------+
*/
boo = malloc(d_1*sizeof(int*));
for (i=0;i<d_1;i++) {
boo[i] = malloc(d_2*sizeof(int*));
for (j=0;j<d_2;j++) {
boo[i][j] = malloc(d_3*sizeof(int*));
for (k=0;k<d_3;k++) {
boo[i][j][k] = i+j*k;
}
}
}
/*
+----------------------+
| Testing the values |
+----------------------+
*/
for (i=0;i<d_1;i++) {
for (j=0;j<d_2;j++) {
for (k=0;k<d_3;k++) {
printf("%d ",boo[i][j][k]);
}
printf("\n");
}
}
return 0;
}
This would essentially do the trick. It might be useful, if you have a greater amount of data.
Don't forget to deallocate the memory using free()

Resources