how to change field in a loop - loops

im trying to allocate memory for 3 different fields and every time i need to check if the malloc fails.
is it possible to make it cleaner using a loop?
newContact->firstName = malloc(((int)strlen(newFirstName) + 1) * sizeof(char));
if (newContact->firstName == NULL) {
printf("The addition of the contact has failed!");
//free
exit(1);
}
newContact->lastName = malloc(((int)strlen(newLastName) + 1) * sizeof(char));
if (newContact->lastName == NULL) {
printf("The addition of the contact has failed!");
//free
exit(1);
}
newContact->phoneNum = malloc(((int)strlen(newPhoneNum) + 1) * sizeof(char));
if (newContact->phoneNum == NULL) {
printf("The addition of the contact has failed!");
//free
exit(1);
}
i know i can make a function that takes the pointer and checks inside of it, but what happens if i need to assign to 10 fields? 50 fields? i want to go over all of the fields or certain parts of, and both assign and check for failure in a loop if possible.

As long as you know the size for each element of the struct, you could just iterate by raw memory addresses and skip sizeof(field) bytes of memory each time. It seems that all of the fields are strings (char pointers), so it shouldn't be too difficult to implement
Something like this:
char* start = ...;
for (char* offset = 0; offset < numberOfFields; offset++)
Now the pointer start + offset would point at the current field. Note that the code above expects all of the fields to be char*. If you want to add more types, then the loop should be adapted to use void* and to skip the ad

Related

Delete the last value of dynamically allocated array in C

The question is in the title
void deleteLastValue(dynIntArray* t){ //function should responds to unexpected values
if(t->tab == NULL){ //if the array is empty we should return an error
fprintf(stderr,"The array is empty");
exit(1);
}
t->tab[(t->size)-1] = 0; /**I'm not sure what to do here should I free the pointer using free function**/
//t->tab[(t->size)-1] = NULL; is it necessary ?
//free(t->tab[(t->size)-1]);
t->tab = (int*)realloc(t->tab,((t->size)-1)*sizeof(int)); //we reallocate but with the new size
t->size--;//size - 1; but capacity stills the same
}
typedef struct{ //structure of an dynamic array
int * tab; //an array of
unsigned int capacity; // the space in memory
unsigned int size;// size of array
} dynIntArray;
If you can review my code, I had issues with what to do with the last element of the array. And should I do more if I want the program to respond to unexpected inputs to make it work properly. Thank you.
You are awesome!
Apparenty it's not quite clear to you how capacity and size are related.
realloc can be a pretty expensive function that may take quite some time. So if you call realloc each and every time the size changes your code will work, but it might be pretty slow. Therefore the capacity is used.
Roughly it is done like this:
You initialize the dynamic array with a size = 0 and capacity = 100 (or some appropriate value larger than 0).
Now you can add 100 elements to the array without realloc ever being called.
If you add one element more, you add 100 to capacity and you call realloc
Now the capacity is 200 and you can add another 100 elements without realloc being called.
If you want to decrease the size of the dynamic array, you just can decrease size without calling realloc leaving capacity alone.
If the difference between size and capacity becomes larger than some value or maybe if the capacity is larger than twice the size, then you can decrease the capacity and call realloc
There are several strategies about how size and capacity are related and when to increase/decrease capacity.
void deleteLastValue(dynIntArray* t) {
if (t->tab == NULL) {
fprintf(stderr, "The array is empty");
exit(1);
}
t->size--; // that's all you need to do
// now optionally you might want to decrease the capacity
// if the capacity is larger than twice the size
// or based on some other strategy
if (t->capacity > 2 * t->size)
{
t->capacity = t->size;
t->tab = realloc(t->tab, t->capacity);
if (t->tab == NULL) {
fprintf(stderr, "realloc error in deleteLastValue");
exit(1);
}
}
}
Be aware that you still need to check if the array is empty (IOW if size is 0. I leave this as an exercise.
If you want more information, you should show us the other functions.
Review of your function:
void deleteLastValue(dynIntArray* t) {
if (t->tab == NULL) {
fprintf(stderr, "The array is empty");
exit(1);
}
t->tab[(t->size) - 1] = 0; // this is useless, the element is no longer part of the array
// you don't need to overwrite it with 0
// the call to free below is completly wrong, t->tab[(t->size) - 1] is not a pointer but an int
// free(t->tab[(t->size) - 1]);
// this reallocation is correct (except there is no error checking and the (int*) cast is useless)
t->tab = (int*)realloc(t->tab, ((t->size) - 1) * sizeof(int));
t->size--;
// you leave the capacity alone which is maybe what you want
}
As you realloc every time, you only need the size of the array. You can also use a flexible array simplifying the allocation and deallocation.
typedef struct{ //structure of an dynamic array
unsigned int size;// size of array
int tab[]; //an array of
} dynIntArray;
dynIntArray *deleteLastValue(dynIntArray* t)
{
if(t && t -> size)
{
t = realloc(sizeof(*t) + (t -> size - 1) * sizeof(t -> tab[0]));
if(t) t -> size--;
}
return t;
}
Thank y'all! It worked perfectly fine. I submit the answer here for posterity. (For the sake of the exercise we don't need to change the capacity)
void deleteLastValue(dynIntArray* t){
if(t->tab == NULL || t->size == 0){
fprintf(stderr,"The array is empty");
exit(1);
}
t->size--;
}

Intentionally hiding memory via malloc

So I'm working on a small memory allocation package, and I've wanted the initialization of pointers to save the size of the space allocated as well as an indicator that it was allocated via one of my functions (which is the character 'q' before the size in memory). So, I've tried to do the following:
int qmem_alloc(unsigned num_bytes, void ** rslt){
*rslt = malloc(num_bytes+sizeof(int)+sizeof(char));
*((int*)rslt) = num_bytes;
*(char*)(rslt+sizeof(int)) = 'q';
rslt = rslt+sizeof(int) + sizeof(char);
if(*rslt == NULL)
return -1;
else if(errno != 0){
//Catch the rest of the errors
return -2;
}
return 0;
}
However, it seems in my main function that the memory directly before the address of rslt does not contain what it should after being passed back. Am I doing something bad here by changing the pointer address?
You're missing a level of indirection in a few places. Anyplace you use rslt before dereferencing you should be using *rslt:
int qmem_alloc(unsigned num_bytes, void ** rslt){
*rslt = malloc(num_bytes+sizeof(int)+sizeof(char));
if(*rslt == NULL)
return -1;
*((int*)*rslt) = num_bytes;
*(char*)(*rslt+sizeof(int)) = 'q';
*rslt = *rslt+sizeof(int) + sizeof(char);
if(errno != 0){
//Catch the rest of the errors
return -2;
}
return 0;
}
Also, the memory returned by malloc is properly aligned for any use. Because you return sizeof(int)+sizeof(char) == 5 bytes past that (assuming a 4 byte int) which means the pointer you return is probably not. You'll want to add at least 3 more bytes to put the returned buffer on an 8 byte boundary.
Within your function rslt is the address of the pointer. You should not be modifying or even accessing that. If you're trying to change/read the address where the pointer is pointing to, than you need to use *rslt. If you're trying the modify/read the value of what the pointer is pointing to, you need to use **rslt.
#dbush describes the result of the above in code.

Why does realloc() fail where malloc() succeds in C?

On RHEL6, I'm facing a strange problem with realloc(). At some point in the program, realloc() returns NULL (the old pointer has an address and there's plently of memory available). What's being allocated is 200 structure elements (structure below). For some reason, when I do a realloc() instead, it works, but I then have to assign the old pointer to the new one. Below is a simplified version of my code.
This is perhaps a server tuning issue more than a programming one. What is your opinion?
Thanks.
//hearder file
typedef struct { /* Variable Node Detail Record */
long next;
long mask;
char *value;
// more stuff...
} NODETEST;
extern NODETEST *oldNodes;
extern NODETEST *newNodes;
//program
#define MAXSIZE 200
// do some stuff with oldNodes....
int alloc_nodes (void)
{
// Allocate or grow the table
oldNodes = (NODETEST *) malloc(MAXSIZE * sizeof(NODETEST));
if( oldNodes == NULL ) {
//handle exception...
exit(1);
}
//oldNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** FAILS
newNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** WORKS
if( newNodes == NULL ){
printf("errno=%d\n", errno );
}else{
oldNodes = newNodes; }
}
Your first call malloc with a size S and then realloc with the same size S. This is wrong: you have to pass to realloc the new wanted size (independently of the current size - it is not an increment). Here, there is a big chance realloc returns exactly the same pointer it received. BTW it is not clear why you want to do with a malloc immediately followed by a realloc. Gives us more detail.
If you want a dynamic table whose size auto-adjusts, you need to allocate an initial size storing its size in a variable (e.g. alloc_size) and keep the current number of occupied elements in another variable (e.g. n_elem) . When you add an element you increment this number. When the table is full reallocate it. Here is a sketch
NODETEST *newNodes = NULL;
int allocated_elem = 0;
int n_elem = 0;
#define ALLOC_INCR 200
then at each addition:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size += ALLOC_INCR;
nodes = (NODETEST *) realloc(nodes, alloc_size * sizeof(NODETEST));
if (nodes == NULL) {
//handle exception...
exit(1);
}
}
// add your element at nodes[n_elem]
n_elem++;
Recall that realloc acts like malloc when the received pointer is NULL (case of the first call). Thus it allocates the initial table. Subsequent calls reallocate it by adjusting the size with a constant increment (here 200). Some other schemes are possible for the enlargement of the table, for instance you can multiply the size by a factor (e.g. 2) starting from 32:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size = (alloc_size == 0) ? 32 : alloc_size * 2;
Regarind the FAIL and WORKS comments: it is clear that if you assign oldNodes (in the FAIL code) then newNodes is not assigned and keeps its initial value which is zero (NULL) since it is declared as a global variable and not initialized (well I suppose, it is extern here). Thus the test if (newNodes == NULL) will probably fail.

dynamically resizing an array of strings

I need an array of strings in which the length of the array is not known at compile time. what I've done is:
char **words;
words = malloc(capacity * sizeof(char *));
char nextword[MAX_LEN + 1];
while (true) {
if (num_entries == capacity) {
capacity += 5;
realloc(words, (sizeof(char *) * capacity));
}
printf("\nEnter a word: ");
fgets (nextword, MAX_LEN, stdin);
remove_newline(nextword);
if (strlen(nextword) == 0) break;
words[num_entries] = malloc(strlen(nextword + 1));
if (words[num_entries] == NULL) {
printf("\nout of space\n");
break;
}
strcpy(words[num_entries], nextword);
num_entries++;
this seems to work to expand the size once, except that the first element after the expansion has become NULL for some reason. The second time realloc is executed I get an error:
"invalid next size".
realloc is not guaranteed to give you back the same chunk of memory, because the block that was originally allocated from the heap may not have enough space to accommodate your new requested size. In this case you will get back a new block of memory, with your old data copied to it.
You need to capture the returned value on each loop and use it to check for the data you expect, and also check for it being 0 (if the realloc cannot be done).
words = realloc(words,..)
is an antipattern - avoid this since your old memory can get lost if the realloc fails.
Your code is almost there, just need a few modifications. An important thing to remember is that realloc does not modify the value that you pass to it, and it is not required to return the pointer to the same chunk of memory that you passed to it. Here is a working example of using realloc. It is rather straightforward, so you should be able to fix your code by simply following the example.
char **more_words = realloc(words, capacity);
if (more_words) {
words = more_words;
} else {
// Do something about realloc failure
}

Resizing an array with C

I need to have an array of structs in a game I'm making - but I don't want to limit the array to a fixed size. I'm told there is a way to use realloc to make the array bigger when it needs to, but can't find any working examples of this.
Could someone please show me how to do this?
Start off by creating the array:
structName ** sarray = (structName **) malloc(0 * sizeof(structName *));
Always keep track of the size separately:
size_t sarray_len = 0;
To increase or truncate:
sarray = (structName **) realloc(sarray, (sarray_len + offset) * sizeof(structName *));
Then set the size:
sarray_len += offset;
Happy to help and hope that helps.
The realloc function can be used to grow or shrink an array. When the array grows, existing entries retain their value and new entries are uninitialized. This may either grow in-place, or if that was not possible, it may allocate a new block elsewhere in memory (and behind the scenes, copy all the values over to the new block and free the old block).
The most basic form is:
// array initially empty
T *ptr = NULL;
// change the size of the array
ptr = realloc( ptr, new_element_count * sizeof *ptr );
if ( ptr == NULL )
{
exit(EXIT_FAILURE);
}
The multiplication is because realloc expects a number of bytes, but you always want your array to have the right number of elements. Note that this pattern for realloc means you do not have to repeat T anywhere in your code other than the original declaration of ptr.
If you want your program to be able to recover from an allocation failure instead of doing exit then you need to retain the old pointer instead of overwriting it with NULL:
T *new = realloc( ptr, new_element_count * sizeof *ptr );
if ( new == NULL )
{
// do some error handling; it is still safe to keep using
// ptr with the old element count
}
else
{
ptr = new;
}
Note that shrinking an array via realloc may not actually return memory to the operating system; the memory may continue to be owned by your process and available for future calls to malloc or realloc.
From http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
/* realloc example: rememb-o-matic */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int input,n;
int count=0;
int * numbers = NULL;
do {
printf ("Enter an integer value (0 to end): ");
scanf ("%d", &input);
count++;
numbers = (int*) realloc (numbers, count * sizeof(int));
if (numbers==NULL)
{ puts ("Error (re)allocating memory"); exit (1); }
numbers[count-1]=input;
} while (input!=0);
printf ("Numbers entered: ");
for (n=0;n<count;n++) printf ("%d ",numbers[n]);
free (numbers);
return 0;
}

Resources