Problem in truncating c array - c

I declared an array and take input from user. Now i want to check duplicate entries, they have to be deleted and memory should be freed. Is it possible to free memory.
freeing the unused memory and reducing the array size?
I entered [10,21,3,4,4,2,6,7,21,4,10].it should get truncated as [10,21,3,4,2,6,7] and array length should now be 7,and i don't want to use sorting.

In C, you cannot change the size of an array. If you use dynamically allocated memory (with malloc()), you can use realloc() to resize the memory region, or allocate a new region, copy the data into it and free the old one.
A solution that is often acceptable is to simply leave part of the array unused. This is done by recording how many entries are used in a separate integer variable.

Simple implementation:
When you do find a duplicate entry, shuffle the array left to fill the gap (covering the duplicate).
Use realloc to reduce your allocation.
Note that you simply can't delete an arbitrary memory location. If runtime for filling gaps is a problem, consider an alternate structure such as a linked list, which would allow removal from the middle.
Removing duplicate entries is another problem. The general case involves sorting. You may have a special case which allows for better behavior.

I declared an array of length 100 and took input from user
so you mean like this:
int input[100];
/* - ask 100 input from user */
Is it possible to free memory
the answer is no because you statically allocate 100 integers.
If you want to be able to reduce memory then you should do something like this:
int *tempBuffer=malloc(100*sizeof(int)); /* dynamic allocation */
for(i=0;i<100;++i) scanf("%d",&tempBuffer[i]);/* - ask 100 input from user */
int uniqueN=10 /* - assume the first 10 entries are the unique entries */
int *realBuffer=malloc(uniqueN*sizeof(int)); /* - allocate new buffer just enough for the unique entries */
for(i=0;i<uniqueN;++i) realBuffer[i]=tempBuffer[i]; /* - copy the unique entries from input to the final buffer */
free(tempBuffer); /* - tempBuffer is now unused, free it */
/* here we have realBuffer with just enough size, no unused memory */
Another solution is to realloc tempBuffer after arranging the first uniqueN entries to be the unique entries:
realloc(tempBuffer,uniqueN);
don't forget to check if malloc or realloc returns NULL

Arrays are not dynamic in C. That said, you can access entries beyond the last one (given that an array variable is essentially a pointer). However, this is not safe.
Also, you cannot delete "array entries". You can move the rest of the elements to occupy the respectively previous positions. However, you cannot actually delete the area occupied by the element since an array is a contiguous piece of memory.

Related

Can I have an array with indeterminate length in C?

so I am a beginner in c, and I am doing this program where a user input values in an array and if the value is 101 then the program is finished. the thing is I don't want the length of the array to be initialized, rather when the user enter 101 there would be the last value and the last place in the array. for example they entered 101 in the third place then the length of the array would be 4. I don't know if that possible.
#include <stdio.h>
int main(void) {
int i,j;
int a[i];
for(i=0;i<10;i++)
{
printf("Enter Value Nummber %d:",i);
scanf("%d",&a[i]);
if
(a[i] == 101) break;
else continue;
}
Here I put the max length could be 10 but, if the user for example gives just 4 values and then 101 then it gives the rest of spots garbage values.
In this case
int a[i];
is called a variable length array, and you're using i unitialized, and that can invoke undefined behaviour. You need to have a defined value of i before you can use it.
That said, the cleaner approach will be (without using dynamic allocation and re-sizing)
Define a higher limit (#define MAXLEN 100) and use that to create an array, and initialize it to a value (say, 0).
Keep on asking user for the inputs, until (whichever is earlier)
You get a value 101
Counter reaches MAXLEN
Otherwise, if you're okay with using allocated memory (malloc()/ realloc() and family), then:
Define a starting size (#define INITSIZ 32)
Allocate memory for that size using malloc().
Ask user for inputs.
If you get an input value of 101, free() the allocated memory and exit.
Otherwise, once you hit the size, double the allocation using realloc() and continue to previous step.
I recommend having a look at malloc. It allows you to dynamically allocate memory and gives you a pointer to the start of the allocated piece of memory.
You can access an element with a pointer that points to the first element and then increase the pointer every time you add a value. Unlike other languages, C does not prevent you from accessing values outside of an array, so track the number of items added with a counter, and make sure to stay within your allocated memory (so save the length in a variable). You can then replace the for loop with an infinite loop, and break once the user inputs the value 101. When you reach the limit of your allocated memory, you can allocate a new array twice the size (so make sure to save the length in a variable) and copy the previous array there, then free the first array.
"Can I have an array with indeterminate length?"
I don't want the length of the array to be initialized, rather when the user enter 101 there would be the last value and the last place in the array. For example they entered 101 in the third place then the length of the array would be 4. I don't know if that possible.
No, it is not possible.
int a[i];
You cannot write to an indeterminate array, as i is not initialized - it holds a garbage value.
Any such attempt is undefined behavior and doesn´t make much sense.
How do you want to store the value the user puts in to the assumed third element if there has not been space allocated for it?
Of course you can use VLAs or allocate and reallocate dynamic memory (as the other two answers suggest) but you can´t write data to memory which isn´t allocated for storing that values.
I do not understand your idea behind. Maybe you explain the bigger goal you want to achieve.

What is the best practice when declaring a user defined array?

What's the best practice when having a user defined array? By user defined, I mean size as well as the element values.
Option A:
Predefine an array of size (lets say) 100, then ask the user how many elements they would like in the array, knowing it will be less than what I have defined.
int array [100];
printf("Input the number of elements to be stored in the array: ");
scanf("%d", &numElements);
Option B:
Declare the array after I ask the user how many elements.
printf("Input the number of elements to be stored in the array: ");
scanf("%d", &numElements);
int array [numElements];
With option A, it could take up unnecessary memory, but I'm not sure when the cons are with Option B, would it be runtime?
As it is tagged C, I will try to answer in the scope of C language.
The second case I think is more prefered than the first one. First of all, for the first case, your array will have constant size and you cannot do realloc on it if a user gives input let's say more than 100, as you will get an error that int[100] is not assignable. For the second case, it is assumed that the given input is the sufficient size to create a constant size array because for the same reasons you cannot realloc to change the size of the array but at least you know the input is given by the user.
My suggestion would be to use a dynamic array which is a bit harder to manipulate as you may have memory leaks, for example, when the elements in your dynamic array are not primitive types but structs or other types that require memory allocation.
However, using dynamic array, you can realloc the size to make it bigger or smaller to save some memory space.
I am new to Stack Overflow so maybe your question is something deeper that my answer will not be enough. BTW, I hope it will give you some hint.
P.S.
Static arrays are always faster to be used, so if you are sure that the number of elements will not be more than a certain number, then it is better to use constant size array.
if using C++ :
{
The best practice is to use the std::vector from the Standard Template Library(STL).
Use reserve() and resize() methods to allocate fixed required space or push_back() and pop_back() to resize according to each insertion and deletion. More about vectors here.
}
else if using C :
{
Use dynamic memory allocation to change the size during runtime using malloc(), calloc(), free() and realloc() defined in <stdlib.h>.
malloc() is used to dynamically allocate a single large block of memory with the specified size. It returns a pointer of type void which can be cast into a pointer of any form.
Syntax:
ptr = (cast-type*) malloc(nbyte-size);
calloc() is used to dynamically allocate the specified number of blocks of memory of the specified type. It initializes each block with a default value ‘0’.
Syntax:
ptr = (cast-type*)calloc(n, element-size);
where n is the number of elements required.
free() is used to dynamically de-allocate the memory. The memory allocated using functions malloc() and calloc() is not de-allocated on their own. Hence the free() method is used, whenever the dynamic memory allocation takes place.
Syntax:
free(ptr);
realloc() is used to dynamically change the memory allocation of a previously allocated memory. If the memory previously allocated with the help of malloc() or calloc() is insufficient, realloc() can be used to dynamically re-allocate memory.
Syntax:
ptr = realloc(ptr, newSize);
}

Is there a way to realloc memory for an array to allow adding additional values to the beginning?

I need to pad the beginning of an existing array with zeros. My current method is to reallocate additional memory for the array, shift every value forward, and then add the zeros.
This is very slow for very large arrays, so I was wondering if there is a method in C to re-allocate memory for the beginning of the array?
For example, if the original size of the array n1=100, and I want to add npad=10 values, is there a way to reallocate such that the array[i] now points to the value previously stored at array[i-npad]?
Not hopeful, but thanks in advance!
What you are requesting is not only not supported by the standard C library but is impossible in theory, except by allocating the potentially needed space at the time of the initial allocation. A routine could give you the illusion of adding space to the beginning in the way that realloc gives the illusion of adding space to the end, but this requires (potentially) moving the data, regardless of whether you do it yourself or have the called routine do it.
For comparison, realloc does not guarantee that it will allocate more space on the end of an array. It might try to allocate more space on the end of an array, but all it guarantees is that it will provide the same data in a larger space, if the space is available. To do this, if it cannot enlarge the existing allocation, it allocates new space and moves the data.
If we attempt to implement a routine that increases an allocation at its beginning, we are faced with a choice at the time of the initial allocation:
Allocate whatever space is available. In this case, the space might be just after other allocated space.
Allocate space with padding of unused space before it.
If we choose the former, the allocation cannot be enlarged at its beginning. If we choose the latter, we are wasting space and must know in advance how much space will be required.
Why not something like
char *GrowArrayAtEnd(char *pOldArray, int nOldSize, int nNewSize)
{ char *pNewArray = (char *)realloc(pOldArray, nNewSize);
memmove(&pNewArray[nNewSize - nOldSize], pNewArray, nOldSize);
memset(pNewArray, 0, nNewSize - nOldSize); // if necessary
return pNewArray;
}

how to allocate memory to store 5 names without wasting not even 1 byte

I want to store 5 names without wasting 1byte , so how can allocate memory using malloc
That's for all practical purposes impossible, malloc will more often than not return blocks of memory bigger than requested.
#include <stdio.h>
#include<stdlib.h>
int main()
{
int n,i,c;
char *p[5];/*declare a pointer to 5 strings for the 5 names*/
for(i=0;i<5;i++)
{
n=0;
printf("please enter the name\n" );/*input name from the user*/
while((c=getchar())!='\n')
n++;/*count the total number of characters in the name*/
p[i]= (char *)malloc(sizeof(char)*n);/*allocate the required amount of memory for a name*/
scanf("%s",p[i]);
}
return 0;
}
If you know the cumulative length of the five names, let's call it length_names, you could do a
void *pNameBlock = malloc(length_names + 5);
Then you could store the names, null terminated (the +5 is for the null termination), one right after the other in the memory pointed to by pNameBlock.
char *pName1 = (char *) pNameBlock;
Store the name data at *pName1. Maybe via
char *p = *pName1; You can then write byte by byte (following is pseudo-codeish).
*p++ = byte1;
*p++ = byte2;
etc.
End with a null termination:
*p++ = '\0';
Now set
char *pName2 = p;
and write the second name using p, as above.
Doing things this way will still waste some memory. Malloc will internally get itself more memory than you are asking for, but it will waste that memory only once, on this one operation, getting this one block, with no overhead beyond this once.
Be very careful, though, because under this way of doing things, you can't free() the char *s, such as pName1, for the names. You can only free that one pointer you got that one time, pNameBlock.
If you are asking this question out of interest, ok. But if you are this memory constrained, you're going to have a very very hard time. malloc does waste some memory, but not a lot. You're going to have a hard time working with C this constrained. You'd almost have to write your own super light weight memory manager (do you really want to do that?). Otherwise, you'd be better off working in assembly, if you can't afford to waste even a byte.
I have a hard time imagining what kind of super-cramped embedded system imposes this kind of limit on memory usage.
If you don't want to waste any byte to store names, you should dynamically allocate a double array (char) in C.
A double array in C can be implemented as a pointer to a list of pointers.
char **name; // Allocate space for a pointer, pointing to a pointer (the beginning of an array in C)
name = (char **) malloc (sizeof(char *) * 5); // Allocate space for the pointer array, for 5 names
name[0] = (char *) malloc (sizeof(char) * lengthOfName1); // Allocate space for the first name, same for other names
name[1] = (char *) malloc (sizeof(char) * lengthOfName2);
....
Now you can save the name to its corresponding position in the array without allocating more space, even though names might have different lengths.
You have to take double pointer concept and then have to put your name character by character with increment of pointer address and then you are able to save all 5 names so as you are able to save your memory.
But as programmer you should not have to use this type of tedious task you have to take array of pointers to store names and have to allocate memory step by step.
This is only for the concept of storing names but if you are dealing with large amount of data then you have to use link list to store all data.
When you malloc a block, it actually allocates a bit more memory than you asked for. This extra memory is used to store information such as the size of the allocated block.
Encode the names in binary and store them in a byte array.
What is "memory waste"? If you can define it clearly, then a solution can be found.
For example, the null in a null terminated string might be considered "wasted memory" because the null isn't printed; however, another person might not consider it memory waste because without it, you need to store a second item (string length).
When I use a byte, the byte is fully used. Only if you can show me how it might be done without that byte will I consider your claims of memory waste valid. I use the nulls at the ends of my strings. If I declare an array of strings, I use the array too. Make what you need, and then if you find that you can rearrange those items to use less memory, decide that the other way wasted some memory. Until then, you're chasing a dream which you haven't finished.
If these five "names" are assembly jump points, you don't need a full string's worth of memory to hold them. If the five "names" are block scoped variables, perhaps they won't need any more memory than the registers already provide. If they are strings, then perhaps you can combine and overlay strings; but, until you come up with a solution, and a second solution to compare the first against, you don't have a case for wasted / saved memory.

how is dynamic memory allocation better than array?

int numbers*;
numbers = malloc ( sizeof(int) * 10 );
I want to know how is this dynamic memory allocation, if I can store just 10 int items to the memory block ? I could just use the array and store elemets dynamically using index. Why is the above approach better ?
I am new to C, and this is my 2nd day and I may sound stupid, so please bear with me.
In this case you could replace 10 with a variable that is assigned at run time. That way you can decide how much memory space you need. But with arrays, you have to specify an integer constant during declaration. So you cannot decide whether the user would actually need as many locations as was declared, or even worse , it might not be enough.
With a dynamic allocation like this, you could assign a larger memory location and copy the contents of the first location to the new one to give the impression that the array has grown as needed.
This helps to ensure optimum memory utilization.
The main reason why malloc() is useful is not because the size of the array can be determined at runtime - modern versions of C allow that with normal arrays too. There are two reasons:
Objects allocated with malloc() have flexible lifetimes;
That is, you get runtime control over when to create the object, and when to destroy it. The array allocated with malloc() exists from the time of the malloc() call until the corresponding free() call; in contrast, declared arrays either exist until the function they're declared in exits, or until the program finishes.
malloc() reports failure, allowing the program to handle it in a graceful way.
On a failure to allocate the requested memory, malloc() can return NULL, which allows your program to detect and handle the condition. There is no such mechanism for declared arrays - on a failure to allocate sufficient space, either the program crashes at runtime, or fails to load altogether.
There is a difference with where the memory is allocated. Using the array syntax, the memory is allocated on the stack (assuming you are in a function), while malloc'ed arrays/bytes are allocated on the heap.
/* Allocates 4*1000 bytes on the stack (which might be a bit much depending on your system) */
int a[1000];
/* Allocates 4*1000 bytes on the heap */
int *b = malloc(1000 * sizeof(int))
Stack allocations are fast - and often preferred when:
"Small" amount of memory is required
Pointer to the array is not to be returned from the function
Heap allocations are slower, but has the advantages:
Available heap memory is (normally) >> than available stack memory
You can freely pass the pointer to the allocated bytes around, e.g. returning it from a function -- just remember to free it at some point.
A third option is to use statically initialized arrays if you have some common task, that always requires an array of some max size. Given you can spare the memory statically consumed by the array, you avoid the hit for heap memory allocation, gain the flexibility to pass the pointer around, and avoid having to keep track of ownership of the pointer to ensure the memory is freed.
Edit: If you are using C99 (default with the gnu c compiler i think?), you can do variable-length stack arrays like
int a = 4;
int b[a*a];
In the example you gave
int *numbers;
numbers = malloc ( sizeof(int) * 10 );
there are no explicit benefits. Though, imagine 10 is a value that changes at runtime (e.g. user input), and that you need to return this array from a function. E.g.
int *aFunction(size_t howMany, ...)
{
int *r = malloc(sizeof(int)*howMany);
// do something, fill the array...
return r;
}
The malloc takes room from the heap, while something like
int *aFunction(size_t howMany, ...)
{
int r[howMany];
// do something, fill the array...
// you can't return r unless you make it static, but this is in general
// not good
return somethingElse;
}
would consume the stack that is not so big as the whole heap available.
More complex example exists. E.g. if you have to build a binary tree that grows according to some computation done at runtime, you basically have no other choices but to use dynamic memory allocation.
Array size is defined at compilation time whereas dynamic allocation is done at run time.
Thus, in your case, you can use your pointer as an array : numbers[5] is valid.
If you don't know the size of your array when writing the program, using runtime allocation is not a choice. Otherwise, you're free to use an array, it might be simpler (less risk to forget to free memory for example)
Example:
to store a 3-D position, you might want to use an array as it's alwaays 3 coordinates
to create a sieve to calculate prime numbers, you might want to use a parameter to give the max value and thus use dynamic allocation to create the memory area
Array is used to allocate memory statically and in one go.
To allocate memory dynamically malloc is required.
e.g. int numbers[10];
This will allocate memory statically and it will be contiguous memory.
If you are not aware of the count of the numbers then use variable like count.
int count;
int *numbers;
scanf("%d", count);
numbers = malloc ( sizeof(int) * count );
This is not possible in case of arrays.
Dynamic does not refer to the access. Dynamic is the size of malloc. If you just use a constant number, e.g. like 10 in your example, it is nothing better than an array. The advantage is when you dont know in advance how big it must be, e.g. because the user can enter at runtime the size. Then you can allocate with a variable, e.g. like malloc(sizeof(int) * userEnteredNumber). This is not possible with array, as you have to know there at compile time the (maximum) size.

Resources