I'm new in c. I want to create array, and after it delete it, and then put another array into it. How can I do it?
If you are looking for a dynamic array in C they are fairly simple.
1) Declare a pointer to track the memory,
2) Allocate the memory,
3) Use the memory,
4) Free the memory.
int *ary; //declare the array pointer
int size = 20; //lets make it a size of 20 (20 slots)
//allocate the memory for the array
ary = (int*)calloc(size, sizeof(int));
//use the array
ary[0] = 5;
ary[1] = 10;
//...etc..
ary[19] = 500;
//free the memory associated with the dynamic array
free(ary);
//and you can re allocate some more memory and do it again
//maybe this time double the size?
ary = (int*)calloc(size * 2, sizeof(int));
Information on calloc() can be found here, the same thing can be accomplished with malloc() by instead using malloc(size * sizeof(int));
It sounds like you're asking whether you can re-use a pointer variable to point to different heap-allocated regions at different times. Yes you can:
void *p; /* only using void* for illustration */
p = malloc(...); /* allocate first array */
... /* use the array here */
free(p); /* free the first array */
p = malloc(...); /* allocate the second array */
... /* use the second array here */
free(p); /* free the second array */
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);
So i have this code:
/* Dynamic Array Reader */
/* Parameters:
* n: Number of values to be read
*
* Returns: pointer to the dynamically allocated array
*/
int *dyn_reader(unsigned int n) {
int* array = malloc(n * sizeof (int));
if (!array)
return NULL;
else {
unsigned int num_read = 0;
printf("Enter %u integers so they can be put into this array\n", n);
while (num_read < n) {
num_read += scanf("%d", array + num_read);
}
}
return array;
}
/* Add to array */
/* Parameters:
* arr: Existing array of integers
* num: number of integers in the array before the call
* newval: new value to be added
*
* Returns: pointer to the allocated array
*/
int *add_to_array(int *arr, unsigned int num, int newval) {
int* newarray = realloc(arr, (num+1) * sizeof (int)); //allocate one more space
if (newarray == NULL) //Return original array if failed to allocate
return arr;
//free(arr); //free old array -- this throws an error when i try and free up the old array
newarray[num] = newval;
return newarray;
}
int main()
{
/* testing exercise. Feel free to modify */
int *array = dyn_reader(5);
array = add_to_array(array, 5, 10);
array = add_to_array(array, 6, 100);
array = add_to_array(array, 6, 1000);
return 0;
}
As you can see, the main function calls dyn_reader which allocates enough memory to allow there to be n elements in the array. It reads in integers from the user and returns the array.
Then the main function calls add_to_array which realocates enough memory to add one addition element in the array. If it cant, it returns the original array. If the memory reallocation works, i add newval to the end of the array. In this case, i am using a new pointer to store where the newly reallocated array. How come when i try to free the old array (free(arr);), i get an error. Doesn't that pointer still point to memory on the heap and shouldnt i free it?
No, if the realloc moved to a new area of memory, then it does the "free()" for you (so make sure you don't have any other pointers pointing into that array ! ). The C standard says (at http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html ) :
The realloc() function shall deallocate the old object pointed to by ptr
The linux man page (at https://linux.die.net/man/3/realloc) makes it more explicit :
If the area pointed to was moved, a free(ptr) is done.
If reallocation was successful, realloc() has handled freeing memory related to the earlier pointer. Note that the pointer may not have even changed.
Another problem with add_to_array() is that the calling function lacks any indication of success/failure.
Example: my array contains integers {1,2,3,4}
I want to resize my array in order to contain {2,3,4} and when I do array[0] it should give me 2.
When you shrink an array with realloc(), you can remove space at the end of the array, but not at the beginning of the array. Therefore, to achieve the result you want, you'd have to copy the portion of the array you want to keep to its new position and then resize the array:
/* setup */
int *data = malloc(4 * sizeof(int)); // Error check omitted
for (int i = 0; i < 4; i++)
data[i] = i + 1;
/* setup complete */
/* Move elements before shrinking array */
memmove(&data[0], &data[1], 3 * sizeof(int)); // Safe move
int *new_data = realloc(data, 3 * sizeof(int));
if (new_data != 0)
data = new_data;
I'm not sure whether a 'shrinking' realloc() does ever return NULL (but the standard doesn't say it can't), so the code takes no chances. Many people would write data = realloc(data, 3 * sizeof(int)); and run the risk, and they'd get away with it almost all the time. Note that a 'growing' realloc() really can return NULL and you can then leak memory if you use the old_ptr = realloc(old_ptr, new_size) idiom.
Usually, a 'shrinking' realloc() will return the original pointer (unless you shrink it to zero size, when it may return NULL). A 'growing' realloc() can often change where the data is stored.
I am trying to make a generic function in C that takes a 2D array of ANY type and copies it into a contiguous memory block. ( I need this function for Aggregate operations on MPI on my complex datatypes).
Imagine I have the following integer array
int n = 5;
int m = 6;
int** int_array = (int**) malloc(n* sizeof(int*));
for (int i = 0; i < n; i++ )
int_array[i] = (int *) malloc(m * sizeof(int) );
In this type of memory allocation one cannot, in principle, hope to access the , say i,j-th entry of int_array using the following pointer arithmetics
int value = (*lcc)[i*m+j];
Therefore I implemented a function that basically allocates a new memory block and neatly orders the entries of int_array so that the above indexing should work.
void linearize(char*** array, int n, int m,unsigned int size_bytes){
char* newarray = (char*)malloc(m*n*size_bytes);
//copy array!
for (int i = 0;i<n;i++)
for(int j = 0;j<m*size_bytes;j++)
{
newarray[i*m*size_bytes+j] = (*array)[i][j];
}
//swap pointers and free old memory!
for (int i = 0;i<n;i++)
{
char * temp = (*array)[i];
(*array)[i] = newarray + i*m*size_bytes ;
free(temp);
}
}
I wanted to make the above function to work with any kind of array type, hence I used char pointers to do operations byte by byte. I tested the function and so far it works, but I am not sure about memory deallocation.
Does free(temp) free the whole memory pointed to by int_array[i], that is the m*sizeof(int) bytes accessible from int_array[i] or only the first m bytes (since it thinks that our array is of type char rather than in) ? Or simply put, "Does the linearize function induce any memory leaks? "
Thank you in advance!
*EDIT*
As suggested by Nicolas Barbey, I ran a valgrind checks for memory leaks and it found none.
So to summarize the main points that I found difficult to understand about the behaviour of the program were:
in the function linearize does the following code induce memory leaks:
char * temp = (*array)[i];
(*array)[i] = newarray + i*m*size_bytes ;
free(temp);
NO!! somehow gnu compiler is smart enough to know how many bytes pointed to by "temp" to free. Originally I was afraid that if I array[i] is a pointer of type int , for example, that points to a memory location with say 5 ints = 5*4 bytes, the free(temp) is going to free only the first five bytes of that memory.
Another point to make is : how to free the already linearized array? that is if you have:
// first initialize the array.
int** array = (int**)malloc(5*sizeof(int*);
for(int i = 0; i< 5;i++)
array[i] = ( int* ) malloc(5*sizeof(int));
//now a call to linearize
linearize(&array,5,5,sizeof(int));
... do some work with array ....
// now time to free array
free(array[0]);
free(array);
//suffices to free all memory pointed to by array[i] and as well as the memory allocated
// for the pointers.
Thanks for the discussion and the suggestions.
You need to call free() exactly one call per malloc() inorder to be no memory leaks. Which means in your case int_array is passed to linearize function allocates a block of memory other than int_array allocation, therefore you need to loop over int_array[i] freeing each int* that you traverse followed by free'ing int_array itself. Also you need to free block created in linearize function too.
Here is a slightly slimmer version using actual two dimensional arrays:
void * linearize(void** array, int n, int m,unsigned int size_bytes){
char (*newarray)[m * size_bytes] = malloc(m*n*size_bytes);
//copy array!
int i;
for (i = 0;i<n;i++) {
memcpy(newarray[i], array[i], sizeof(*newarray));
free(array[i]);
}
free(array);
return newarray;
}
Use:
int (*newarray)[m] = linearize(array, n, m, sizeof(**int_array));
int value = newarray[i][j];
// or
value = newarray[0][i*m + j];
// or
value = ((int *)newarray)[i*m + j];
how can i define an array in c which works like vector? This array should take any amount of values. It can take 0 values or 10 values or 100 values.
The code below works but gives me a runtime error that stack was corrupted.
int i = 0;
int* aPtr = &i;
int* head = aPtr;
for(i=0;i<6;i++){
(*aPtr)=i;
aPtr++;
}
Similarly how can i use char* str to take any amount of characters followed by null character in end to make a string?
Practice for interviews :)
There are many ways to do this in C, depending on your requirements, but you said "any number of values" (which usually means as many as will fit in memory). That's commonly done using realloc to grow the size of an array dynamically. You'll need to keep some bookkeeping information too on the size of the array as it grows.
void
store (vector_t * v, int idx, int value)
{
if (v->size < idx) {
v->size = idx * 2;
v->data = realloc(v->data, v->size);
}
v->data[idx] = value;
}
This being tagged "homework", I've left some details to fill in such as the definition of vector_t.
In Your for loop , after the first iteration, you are trying to access aPtr which points to a memory location which was not declared or reserved before. In the first iteration, the int i did the memory allocation for you.
What you could do though would be to initally allocate the memory required using malloc .
Once this memory is allocated , and if you walk through only the allocated stack space, you wont come across a run time error.
PS:Your code does not work if it just compiles. Any program may contain run time as well as compile time errors. Your code sample is a very common example of run-time error.
This isn't too difficult. The important thing to remember is that you will need to initially allocate memory for your array using malloc(...) or calloc(...). After that you can easily allocate (or deallocate) memory as items are added or removed. The method for dynamically adding or removing memory (which is used to store the items in the array) is realloc(...). The wiki page for C Dynamic Memory Allocation is actually pretty informative. I've provided an example below showing how to initially allocate a char* array, then increase the size and decrease the size.
#include "stdio.h"
#include "stdlib.h"
int main()
{
char *myDynamicString;
/* allocate initial memory */
myDynamicString = (char *)malloc(sizeof(char) * 2);
myDynamicString[1] = '\0';
/* set values */
myDynamicString[0] = 'A';
/* prints: A */
printf("String: %s\n", myDynamicString);
/* make string bigger */
myDynamicString = (char *)realloc(myDynamicString, sizeof(char) * 6);
myDynamicString[5] = '\0';
/* set values */
myDynamicString[1] = 'P';
myDynamicString[2] = 'P';
myDynamicString[3] = 'L';
myDynamicString[4] = 'E';
/* prints: APPLE */
printf("Bigger String: %s\n", myDynamicString);
/* make string smaller */
myDynamicString = (char *)realloc(myDynamicString, sizeof(char) * 3);
myDynamicString[2] = '\0';
/* set values */
myDynamicString[1] = 'Z';
/* prints: AZ */
printf("Smaller String: %s\n", myDynamicString);
/* don't forget to release the memory */
free(myDynamicString);
return 0;
}