I am writing a program in which I have to manage an array of strings. Throughout the program, the strings are systematically removed/modified until only a single string remains.
I remove the strings when they are no longer needed using this function:
void remove_element(char **array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1];
}
free(array[array_length]);
}
Once I am totally done with the array, I use this function to ensure all the strings are free'd:
void free_fragments(char **frags){
int i = 0;
while((frags[i] != NULL) && sizeof(frags[i] != 0)){
free(frags[i]);
i++;
}
free(frags);
}
Yet, when I do this, valgrind gives me an "Invalid free() / delete / delete[] / realloc()" error, specifically complaining about the "free(frags[i])" line in free_fragments.
I understand that free_fragments seems kind of redundant, simply because theoretically I can call remove_element on each element until there is one remaining and then remove_element that as well, but when I try to do that, I still get a Invalid free() error, but this time complaining about remove_element. If I don't call free_fragments when I am done with the array, I get a memory leak.
My understanding of pointers is pretty beginner, so please help me debug this and improve my understanding!
The problem is that while you do free(array[array_length]);, you do not NULL it out, so in free_fragments you still think it is a valid pointer.
Come to think of it, you seem to free, the wrong entry, too... This should work:
void remove_element(char **array, int index, int array_length)
{
int i;
free(array[index]);
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1];
}
array[array_length-1] = NULL;
}
Assuming that index refers to index of string in 2d array which you want to free, I believe that there is a memory leak in your program. Wouldn't the memory address of string to be freed be lost in the first iteration: array[index] = array[index + 1].
Also you are going outside array's boundary in the last statement and freeing entirely something else. Basically there is a memory leak and you should free the string before overwriting its address with neighbouring strings as defined in #LaszloLadanyi's solution.
void remove_element(char **array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1];
}
/* Array indexes in C are in the range [0 - length-1]. Here
you are going outside array boundaries.
*/
free(array[array_length]);
}
I think you need to modify you codes to
void remove_element(char **array, int index, int array_length)
{
int i;
for(i = index; i < array_length - 1; i++){
array[i] = array[i + 1]; //I don't understand what's purpose here
}
free_fragments(array); //array[array_length] is a invalid pointer, out of range
}
Related
So basically according to definition of array we cannot change array size. But if I am adding element to a same array by shifting other elements to the right of array, so the array size is going to increase.
How this is possible?
#include<stdio.h>
int main() {
int n, j, k, item;
printf("Enter size of array:\n");
scanf("%d", &n);
printf("Enter element to insert and position of element:\n");
scanf("%d,%d", &item, &k);
int a[n];
for (j = 0; j < n; j++) {
printf("Enter a[%d] element:\n", j);
scanf("%d", &a[j]);
}
j = n - 1;
while (j >= k - 1) {
a[j + 1] = a[j];
j = j - 1;
}
a[k - 1] = item;
for (j = 0; j <= n; j++) {
printf("%d\n", a[j]);
}
}
Shifting the contents of the array to the right will not resize the array. If the array was not already large enough to hold the result of the shift, then you have overrun the array object, and have induced undefined behavior.
There is no way to dynamically increase the size of a variable with static or auto duration (e.g., global or local variables), and this includes arrays. If your compiler supports variable length arrays (VLAs), changing the value of the expression controlling the dimension of the array does not affect the array's size.
int main (void) {
int n = 3;
int v[n];
printf("%zu\n", sizeof(v));
++n;
printf("%zu\n", sizeof(v));
}
The program above will print the same value twice.
I am not entirely sure what you're asking, but for any readers interested in knowing how to dynamically change the size of an array in C: if an array is declared in stack memory, its size cannot change. However, a block of memory intended to be used as an array is declared on the heap (i.e. with malloc or calloc), can be reallocated with a different size if necessary:
int *data = malloc(10 * sizeof(int)), *data2 = NULL;
int i;
if(data == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
for (i = 0; i < 10; i++)
{
data[i] = i;
}
data2 = realloc(data, 11 * sizeof(int));
if(data2 == NULL)
{
free(data);
perror("realloc");
exit(EXIT_FAILURE);
}
else
{
data = data2;
}
data[10] = 10;
for (i = 0; i < 11; i++)
printf("%d ", data[i]);
free(data);
data = NULL;
Shifting elements in an array down one element will not change its size.
If you declare an array as
T a[N]; // assume N is a constant expression
then a can only ever hold N elements of type T - no more, no less. You cannot add extra elements to the array, nor can you remove elements from the array.
However...
C does not force any bounds checking on array subscripting, so it's possible that you can read or write past the end of the array such as
a[N + 2] = x;
The behavior on doing so is undefined - your program may work as expected, or it may crash immediately, or you may corrupt other objects in the program. The runtime environment will (most likely) not throw an IndexOutOfBounds-type exception.
There is a thing called a variable-length array that was added in C99, where the array size is not a constant expression:
size_t size = some_value();
T a[size];
Variable length arrays are only variable length in the sense that their size isn't determined until runtime - however, once defined, their size is fixed throughout their lifetime, and like regular arrays, they cannot grow as new items are added.
If you dynamically allocate a chunk of memory using
T *a = malloc( sizeof *a * some_size );
then you can grow or shrink that chunk of memory using realloc:
T *tmp = realloc( a, sizeof *a * (some_size * 2) );
if ( tmp )
{
a = tmp;
some_size *= 2;
}
.... array we cannot change .. But if I (do something special) ... the array size is going to increase.
How this is possible?
Undefined behavior
Arrays cannot change size once defined.
Code attempts to assign a[j + 1] with j = n-1 and that is a[n]. This is outside array a[] and so undefined behavior. Rest of code is irrelevant for at that point anything is possible, code crash, error report, even apparent successful array expansion, etc.
int a[n];
...
j = n - 1;
while (j >= k - 1) {
a[j + 1] = a[j]; // To attempt access to `a[n]` is UB
For class I have to make a Selection Sort function recursively with no loops. I finally got it to compile with no errors, but now it just says "segmentation fault (core dumped)". I'm pretty new to C so please explain what this means. I'm assuming that there's a stack overflow, but I can't see where or how.
Here are my two functions involved in Selection Sort.
void CheckRemaining(int arr[], int minpos, int len, int j) {
if (j == len - 1) {
return;
}
if (arr[minpos] > arr[j]) {
minpos = j;
}
CheckRemaining(arr, minpos,len, j + 1); //j increments with each iteration
}
void SelectionSort(int arr[], int len) {
int i = 0;
int j;
int minpos;
minpos = i;
if (i == len - 2) {
return;
} else {
j = i;
CheckRemaining(arr, minpos,len, j);
swap(&arr[minpos], &arr[j]);
SelectionSort(&arr[i++], len); //The location in the array increments
}
}
int main() {
int i;
int len;
int arr[] = {5,7,3,2,9,4,10};
len = sizeof(arr)/sizeof(arr[0]);
SelectionSort(arr,len);
for ( i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
return 0;
}
Am I missing something big here?
You are most likely correct that you have a stack overflow, because the recursion will never end.
The problem is that you use the local variable i in the condition to terminate the recursion, but you forget that local variables are local for each call. Every time the SelectionSort is called, there will be a new i variable initialized to zero, so the recursion will never end.
SelectionSort(&arr[i++], len);
I think, it should not work for this code. The recursion will never end. Every time you are calling to SelectionSort() and initializing i with 0. So i will never be len-2. Each time this function is getting a different i.
int i=0;
You defined i as a local scope variable, meaning that every time is called, i=0 is taking effect, preventing you from ever having any i greater then 0, thus this condition:
if (i==len-2)
will never be true. Hence, you get an infinite loop.
By the way, to answer to you about the segfault, when you have a segmentation fault, it means that you wanna reach a "forbidden" memory area, for example (usual error in beginning) when you didn't malloc'd a string/tab and your loop's index is "too far" you want to access to a "forbidden" area then it segfault.
I am running in a loop the following function:
int* rpermute(int n)
{
int* a = malloc(n * sizeof(int));
int k;
for (k = 0; k < n; k++)
{
a[k] = k;
}
for (k = n - 1; k > 0; k--)
{
int j = rand() % (k + 1);
int temp = a[j];
a[j] = a[k];
a[k] = temp;
}
return a;
}
If I set a new int variable in my code every variable is changing, I assume it is a buffer overflow problem.
Running the valgrind i get the following:
==4459== 73,036 bytes in 19 blocks are definitely lost in loss record 1 of 1
==4459== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4459== by 0x402CFB: rpermute (in /home/giwrgos/Desktop/crowdv22/crowd_evacuation)
==4459== by 0x403378: main (in /home/giwrgos/Desktop/crowdv22/crowd_evacuation)
I use linux through the virtualbox but I have set enough storage and ram, what should I do?
EDIT: See poster's comment below, the problem is not in this code after all.
You should simply free() the memory allocated in and returned by rpermute(). This must be done in the code from where you call rpermute(), once you're done with this array.
I understand that you regenerate this array for differing int values (the n parameter of rpermute()). Perhaps you simply assign a new output to the array you keep:
int* array;
...
array = rpermute(100);
// Some time later.
array = rpermute(200); // Previous array memory is leaking.
You should do instead:
free(array);
array = rpermute(200);
Note that this is not a 'buffer over flow', but a memory leak instead. I checked you code for buffer overflow: index of a points outside it, but this seemed to be ok in both loops.
I have a small program that generates an SHA1 digest for arguments passed via command line and stores them in an array of pointers to char arrays (I think):
#include <stdio.h>
#include <openssl/sha.h>
int entries = 0; // Keep track of entries added
int main(int argc, char **argv)
{
// Allocate space for the digest array
unsigned char **mds = malloc(1);
// Add entries to the digest, one for each argument passed
for(int k = 1; k < argc; k++) {
mds[k - 1] = malloc(SHA_DIGEST_LENGTH);
SHA1(argv[k], strlen(argv[k]), mds[k - 1]);
entries++;
}
// Print each 20-byte digest
for(int j = 0; j < entries; j++) {
for(int i = 0; i < SHA_DIGEST_LENGTH; i++) { printf("%02x ", *(mds[j] + i)); }
printf("\n");
}
}
Originally I had unsigned char **mds = calloc(argc, SHA_DIGEST_LENGTH); and I was going to try to use realloc() everytime I wanted to add another entry (if I didn't know how many entries I was going to have later).
But then I found out that I didn't need to do that and I didn't even need to allocate any space at all? Just a byte and it still works just fine. That doesn't seem right to me.
Am I just lucking out or something? What am I missing?
Am I just lucking out or something?
Yes.
What am I missing?
Your program writes outside of the allocated memory. Doing so causes undefined behaviour. Anything could happen, including the appearance of correct behaviour.
Adding some free() calls will probably turn up some crashers, but no guarantees - undefined behaviour is undefined, after all.
You are writing in memory not allocated to you. Lucky that you have no crashes so far.
Try using valgrind if it is available on your platform. It will tell you about memory errors both of this variety and when you allocate memory that you forget to free. The program will run slower but you only need to do it for testing purposes.
This part:
// Allocate space for the digest array
unsigned char **mds = malloc(1);
allocates a memory block of size 1 byte and casts its address to unsigned char**. Then later in the first iteration already, when you do:
mds[k - 1] = malloc(SHA_DIGEST_LENGTH);
the malloc returns an address, which is written into the invalid memory causing undefined behavior.
You need to allocate appropriate memory block that will hold pointers and in every iteration you will initialize each of these pointers to point to the memory block that will hold string:
// allocate array of pointers:
unsigned char **mds = malloc( (argc - 1) * sizeof(unsigned char*) );
for (int k = 1; k < argc; k++) {
mds[k - 1] = malloc(SHA_DIGEST_LENGTH);
SHA1(argv[k], strlen(argv[k]), mds[k - 1]);
entries++;
}
...
// cleaning up:
for (int k = 1; k < argc; k++) {
free(mds[k - 1]);
}
free(mds);
I'm new to C and I'm having a small problem with my code:
int i, n;
int *arr;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
exit(1);
else {
arr = (int*) malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
} //end if
} //end while
What I'm trying to do is to make an array of n size and I want to stop reading when I get a '0' for example if I enter:
3
2
2
5
2
6
7
0
I want an array of size 3 with values 2, 2, 5, an array of 2 with values 6 and 7 and exit because of the 0
* Sorry, I left out an important part I think... In my code a call a calc() where I send arr, right after scanf("%d",&arr[i]) and then i'll return the value and then if the next values e.g. 2 isn't 0 I'll read, create a new array, send arr, print result on console and again if the next value is 0 then it will exit. *
Could you guys tell me where I'm wrong?
You are almost there!
You are creating the new arrays in arr, but this is a single pointer so can only refer to one block of memory. When you call malloc the new memory is stored in arr but the old memory is lost. You are 'leaking memory' because the machine has the old memory reserved but you don't have a variable storing it's address so you have no way to find it again.
If you only need to store the last list you should free the old memory (in arr) before malloc'ing the new space. If you need to store all the arrays you will need an array of pointers in arr.
edit:
You need to call free to 'free' the previously allocated memory before you allocate the new memory. At the first set of data you don't have any existing 'malloc' but it's always safe to free a NULL pointer, so simply set the pointer to NULL at the start.
Hint: It's always a good idea to set all the variables to some safe initial value when you define them.
int *arr=NULL; // Mark this as pointing to no memory
....
free(arr); // first time it does nothing, afterwards it deletes the previous reserved memory
arr = (int*) malloc(sizeof(int) * n); // as before this reserves some memory
The problems which are visible in your code are:
1. Checking uninitialized integer n in while. To fix this either initialize n to non zero or use a do{ ... } while() instead of while().
2. You need to validate the value of n which is read through scanf. malloc takes size_t type as the parameter which is unsigned int. But n being an integer can accept negative values, thus if a negative value is entered it will be passed as unsigned int to malloc, this may lead to undesired results (Also for loop will be executed incorrect number of times). You may also consider changing the type of n from integer to unsigned int type or change the exit condition to if( n < 1 ).
3. There is memory leak in your program. Memory allocated through malloc is not freed through free.
4. Do not assume that malloc will always succeed. Please check for the success of malloc through a NULL check i.e.
if (NULL == arr)
{
//error handling
}
5. exit with non zero value generally indicates abnormal termination. You can use break or return. break might be a better idea as it generally gets difficult to test a function as the exit points in the function increase (though this may not be true in your case, but it is FYI)
6. Optionally, you can check the return value of scanf to make sure that a valid input was entered.
Help this helps!
You're not initializing n so you may or may not enter your while loop. Starting n at -1 would be a reasonable thing to do:
int i, n = -1;
And you should cast the return value of malloc, that can hide problems.
You're also leaking memory because you're not calling free on that you get back from malloc and you're losing track of what you read in every time you assign a new value to arr. Brian Roach and Martin Becket have mentioned these things though.
Presumably you want to be able to access these arrays later.
As it is, you're losing your pointer to the previous array when you malloc the next one (and of course, causing a memory leak if it were a larger application).
You need to allocate a chuck of int * (a set of int pointers) then store each int pointer there.
The trick is ... if you don't know how many arrays you're going to need, you need your code to be dynamic (for example; allocate some amount of space, then allocate more if you run out).
Another option is that you could limit the number of series the user can input and tell them they're done when they reach it.
Here's some help if you wanted to go the latter route:
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5); /* max of 5 arrays */
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
HOWEVER ... now you don't know how long each array is. Which is a problem. You'd need to keep track of that, or use a dynamic structure such as a linked list. In the example below, we add the length as the first element of each array:
int main()
{
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5);
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * (n + 1)); /* one more than we need */
arr[0] = n; /* store the array length in the first element */
for(i = 1; i <= n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
int j;
for (i = 0; i < arrayCount; i++)
{
int length = myArrayOfArrays[i][0]; /* retrieve the length */
for (j = 1; j <= length; j++)
printf("%d ", myArrayOfArrays[i][j]);
printf("\n");
}
}
Dynamic allocation using arrays / raw memory means you need to keep track of stuff. The better approach really is using a linked list for your data. In this case, you could have a linked list of nodes, each of which contained a link list of integers.