Can someone find the mistake? Pure C realloc - c

I've got this code:
int main() {
int i=0, n=0;
char sep=NULL;
double **aero=(double**)malloc(sizeof(double*));
*aero=(double*)malloc(2*sizeof(double));
printf("Zadejte souradnice:\n");
while (1) {
aero=(double**)realloc(aero,(n+1)*sizeof(double*));
for (i=0; i<n+1; i++) {
aero[i]=(double*)realloc(aero[i],2*sizeof(double));
}
if ((scanf("[%lf,%lf]%c",&aero[n][0],&aero[n][1],&sep))==3 && (sep=='\n' || sep==' ')) {
n++;
continue;
} else if (!feof(stdin)) {
printf("Nespravny vstup.\n");
freeArray2D(aero,n);
return 0;
}
break;
}
}
It works fine, but I can scanf coordinates (in format: [x,y]) only 19 times. Then it shows me Segmentation fault (core dumped). I use Linux compiler gcc -Wall -pedantic main.c -lm I have no idea, where is the problem. Thanks for any help.

You never assign a fresh malloced buffer to aero[1], but pass the garbage in there to realloc. Maybe you expected the realloc for aero to zero-initalize the memory?

In aero[i]=(double*)realloc(aero[i],2*sizeof(double)), if i == n, then aero[i] is uninitialzed. You should not call realloc on an uninitialized pointer.

Your specific problem is that you realloc a pointer, aero[n], that was never malloced in the first place (and is not necessarily NULL). That's a recipe for disaster.
You also have another issue though it's more an unnecessary-work problem than a fatal flaw. You are re-allocating every single aero[] variable in the loop when they're not actually changing in content or size. It appears to me that all you need to do in the loop is simply increase the size of the first level of memory aero and allocate memory for its new element:
while (1) {
aero = realloc (aero, (n+1) * sizeof (double*));
aero[n] = malloc (2 * sizeof (double));
:
You'll notice I've removed the casting of the malloc return values. This casting is ill-advised in C as it can hide certain subtle errors. C is perfectly capable of converting the void* return values into any other pointer type implicitly.
And, of course, you should never assume that your memory allocations will work - I'd be checking the return values for NULL and exiting immediately if I found one.
The only other issue I had (other than my inability to read Czech of course) was the setting of the char sep to NULL. NULL is usually reserved for pointers rather than characters so it looks more sensible if you initialise it to \0.

Related

Segmentation fault on program with scanf

This is a small piece of code that I made while trying to understand how malloc and pointers work.
#include <stdio.h>
#include <stdlib.h>
int *buffer (int count)
{
int *buffer = malloc (count * sizeof(int));
for (int i = 0; 0 <= i && i < count; i++)
{
buffer[i] = 0;
}
return &buffer;
}
int main ()
{
int size = 0;
int i = 0;
scanf ("%d", &size);
int *num = buffer (size);
while (i < size)
{
scanf ("%d", &num[i]);
i++;
}
}
For some reason that I can't understand, I keep getting a segmentation fault. This error repeatedly happens on the last scanf() and I do not know why. I know i have to pass pointer to scan f and num is already a pointer so i thought that i would not need to include the &. But, I received a segmentation fault earlier if i do not. Also, I believe I have allocated the correct amount of space using malloc but I am not sure. Any help with what is happening here would be appreciated.
You returned the pointer to the local variable buffer, which will banish on exiting the function buffer.
You should remove the & used in the return statement and return the pointer to allocated buffer.
Also checking whether malloc() is successful should be added.
There are a couple of issues that I can see, and one of them is definitely a problem.
In function, int *buffer (int count)
return &buffer;
This will return address of buffer which is already a local int * variable.
So when the return happens, variable buffer would no longer be valid. Hence, the address is invalid.
One of the ways to go ahead as of now would be avoiding a function call buffer and using calloc().
Because, subject to availability, calloc() will allocate the memory of requested length, which will be initialized to 0 by default.
Or, the other way would be making the buffer pointer a global variable.
Also, with existing implementation, there needs a piece of code which checks if malloc returned anything or not. That would indicate if the memory was allocated or not.
Something like this would do:
int *buffer = malloc (count * sizeof(int));
if(buffer == NULL)
{
// Some error handling
return 0;
}
Additionally, I see the for loop which looks a bit weird than what it should look like:
for (int i = 0; 0 <= i && i < count; i++)
I take that you are trying to loop the count times and fill a 0 in buffer. This could have been achieved by
for (int i = 0; i < count; i++)
So, a malloc() is followed by en error-check and then followed by a for to fill the allocated memory with zeroes. So, using calloc makes life a lot easier.
Importantly, you allocate memory but you don't seem to have a code that de-allocates (frees) it. There are ample of examples to refer for doing that. I would recommend you to read concepts like Memory Leakage, Dangling Pointers and using valgrind or similar thing to validate the memory usage.
As a side-note and not a rule of thumb, always make sure that the names you use for variables are different than the names you use with functions. That creates a hell a lot of confusion. Going ahead with existing naming habit, you'll have a tough day when the code is reviewed.

Allocating large space for dynamic array

we wrote a program that reads comma-separated integer-values into an array and tries processing them with a parallel structure.
By doing so, we found out that there is a fixed limitation for the maximum size of the dynamic array, which usually gets allocated dynamically by doubling the size. Yet for a dataset with more than 5000 values, we can't double it anymore.
I am a bit confused right now, since technically, we did everything the way other posts pointed out we should do (use realloc, don't use stack but heap instead).
Note that it works fine for any file with less or equal than 5000 values.
We also tried working with realloc, but to the same result.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// compile with gcc filename -lpthread -lm -Wall -Wextra -o test
int reader(int ** array, char * name) {
FILE *fp;
int data,row,col,count,inc;
int capacity=10;
char ch;
fp=fopen(name,"r");
row=col=count=0;
while(EOF!=(inc=fscanf(fp,"%d%c", &data, &ch)) && inc == 2){
if(capacity==count)
// this is the alternative with realloc we tried. Still the same issue.
//*array=malloc(sizeof(int)*(capacity*=2));
*array = realloc(*array, sizeof(int)*(capacity*=2));
(*array)[count++] = data;
//printf("%d ", data);
if(ch == '\n'){
break;
} else if(ch != ','){
fprintf(stderr, "format error of different separator(%c) of Row at %d \n", ch, row);
break;
}
}
// close file stream
fclose(fp);
//*array=malloc( sizeof(int)*count);
*array = realloc(*array, sizeof(int)*count);
return count;
}
int main(){
int cores = 8;
pthread_t p[cores];
int *array;
int i = 0;
array=malloc(sizeof(int)*10);
// read the file
int length = reader(&array, "data_2.txt");
// clean up and exit
free(array);
return 0;
}
EDIT: I included the realloc-command we tried and changed the values back to our original testing values (starting at 10). This didn't impact the result though, or rather still does not work. Thanks anyways for pointing out the errors! I also reduced the included code to the relevant part.
I can't really get my head around the fact that it should work this way, but doesn't, so it might just be a minor mistake we overlooked.
Thanks in advance.
New answer after question has been updated
The use of realloc is wrong. Always do realloc into a new pointer and check for NULL before overwriting the old pointer.
Like:
int* tmp = realloc(....);
if (!tmp)
{
// No more memory
// do error handling
....
}
*array = tmp;
Original answer (not fully valid after question has been updated)
You have some serious problems with the current code.
In main you have:
array=malloc(sizeof(int)*10); // This only allocates memory for 10 int
int length = reader(&array, "data_1.txt");
and in reader you have:
int capacity=5001;
So you assume that the array capacity is 5001 even though you only reserved memory for 10 to start with. So you end up writing outside the reserved array (i.e. undefined behavior).
A better approach could be to handle all allocation in the function (i.e. don't do any allocation in main). If you do that you shall initialize capacity to 0 and rewrite the way capacity grows.
Further, in reader you have:
if(capacity==count)
*array=malloc(sizeof(int)*(capacity*=2));
It is wrong to use malloc as you loose all data already in the array and leak memory as well. Use realloc instead.
Finally, you have:
*array=malloc( sizeof(int)*count);
Again this is wrong for the same reason as above. If you want to resize to the exact size (aka count) use realloc

How to Use malloc correctly in C?

I'm trying to allocate some memory using malloc() (I don't have much experience with malloc as I am just starting to learn how to use it), and I am getting a warning before compiling with my IDE.
int numInSeq = 0;
int i;
printf("How many numbers do you have in your sequence: ");
scanf("%d", &numInSeq);
double* sequence = (double*) malloc(numInSeq * sizeof(double));
printf("Enter the sequence of the numbers you have (seperated by spaces): ");
for (i = 0; i < numInSeq; i++) {
scanf("%lf", &sequence[i]);
}
The warning is on the line where I call malloc, and it says:
Implicitly declaring library function 'malloc' with type 'void *(unsigned long)'
Is this in incorrect way of formatting that line of code? The program still compiles, but there are some unexpected results that I get when testing.
Make sure to include <stdlib.h>.
Important points while using malloc :
Malloc function call returns you the void pointer which points to the memory location , So you should cast it to your desired data type pointer explicitly.
You should always remember to free the memory which you dynamically allocated using malloc. (very imp)
You should always check if malloc function call was successful or not.
FYI check this link: http://www.cplusplus.com/reference/cstdlib/malloc/
Hope this helps.
How to use malloc correctly in C?
Be sure to include the correct header file. That fixes OP's compiler warning.
#include <stdlib.h>
Casting the return is allowed but frowned upon in C as being unnecessary. Other may disagree, so best to follow your group's coding standard.
double* sequence = /* cast not required */ malloc(...);
Consider the follow style as it is easier to code, review, maintain and IMO, less error prone.
// object_pointer = malloc(sizeof *object_pointer * num_elements);
// Example
double* sequence = malloc(sizeof *sequence * numInSeq);
Remember the argument type is size_t and may differ in size than int. size_t is the unsigned integer type of the result of the sizeof operator.
void *malloc(size_t size);
Passing a negative int to malloc() acts like:
malloc((size_t) some_negative_int) -->
malloc(some_large_size_t)
Check the result.
if (sequence == NULL) Handle_OutOfMemory();
Eventually, free the pointer. It is OK to free the pointer even if it has a NULL value.
free(sequence);
If there is a chance sequence will get used again after free-ing, best to promptly set its value to NULL.
free(sequence);
sequence = NULL;
An allocation of 0 may or may not return NULL and is not an out-of-memory condition.
double* sequence = malloc(sizeof *sequence * numInSeq);
// If `numInSeq` could have a zero value, add test
if (sequence == NULL && numInSeq != 0) {
Handle_OutOfMemory();
}
Use <stdlib.h> or <cstdlib> as suggested by Scott, also, always make sure malloc return valid pointer by NULL check.
//malloc unable to allocate memory
if(sequence == NULL)
{
//return;
}
At the end, use free to freeup memory and to avoid memory leak.
free(sequence);

*** glibc detected *** realloc(): invalid old size 3

This code sometimes give me a Segmentation fault, why could this be?
void concatenarAlBuffer(char **destino, char caracter)
{
char matrizAux[1];
matrizAux[0]=caracter;
matrizAux[1]='\0';
(*destino) = realloc((*destino),2+(strlen((*destino))*sizeof(char)));
if ((*destino)==NULL)
{
perror("Error al reservar memoria\n");
exit(-1);
}
strcat((*destino),matrizAux);
}
matrizAux can only hold one character. You can't access matrizAux[1] - it's out of bounds.
Declare matrizAux like this:
char matrizAux[2];
Remember that an n-elements array can be indexed in positions 0 up to (and including) n-1.
Also, you don't need sizeof(char), because it it always 1. And parentheses around *destino are useless in this case and make the code harder to read unnecessarily. Here's how I would change your code:
void concatenarAlBuffer(char **destino, char caracter) {
char matrizAux[2];
matrizAux[0]=caracter;
matrizAux[1]='\0';
*destino = realloc(*destino,2+strlen(*destino));
if (*destino == NULL) {
perror("Error al reservar memoria\n");
exit(-1);
}
strcat(*destino, matrizAux);
}
You make
char matrizAux[1];
a 1-char long array.
And then you write to its' second element with
matrizAux[1]='\0';
This might or might not crash depending on what's behind your array in memory.
But it still looks like something's missing.
realloc can reallocate only something that was previously malloc- or calloc-ated.
Trying to reallocate something that doesn't fulfill this condition gives you your error. And that's probably the true case here.
char matrizAux[1] hold only one character. Since you are accessing matrizAux[1], i.e. something out-of-bounds, you are corrupting the memory. This can result in the internal data of the runtime getting corrupted, which results in the segfault during the realloc(), even though the realloc itself is correct.

How to allocate memory for an array of strings of unknown length in C

I have an array, say, text, that contains strings read in by another function. The length of the strings is unknown and the amount of them is unknown as well. How should I try to allocate memory to an array of strings (and not to the strings themselves, which already exist as separate arrays)?
What I have set up right now seems to read the strings just fine, and seems to do the post-processing I want done correctly (I tried this with a static array). However, when I try to printf the elements of text, I get a segmentation fault. To be more precise, I get a segmentation fault when I try to print out specific elements of text, such as text[3] or text[5]. I assume this means that I'm allocating memory to text incorrectly and all the strings read are not saved to text correctly?
So far I've tried different approaches, such as allocating a set amount of some size_t=k , k*sizeof(char) at first, and then reallocating more memory (with realloc k*sizeof(char)) if cnt == (k-2), where cnt is the index of **text.
I tried to search for this, but the only similar problem I found was with a set amount of strings of unknown length.
I'd like to figure out as much as I can on my own, and didn't post the actual code because of that. However, if none of this makes any sense, I'll post it.
EDIT: Here's the code
int main(void){
char **text;
size_t k=100;
size_t cnt=1;
int ch;
size_t lng;
text=malloc(k*sizeof(char));
printf("Input:\n");
while(1) {
ch = getchar();
if (ch == EOF) {
text[cnt++]='\0';
break;
}
if (cnt == k - 2) {
k *= 2;
text = realloc(text, (k * sizeof(char))); /* I guess at least this is incorrect?*/
}
text[cnt]=readInput(ch); /* read(ch) just reads the line*/
lng=strlen(text[cnt]);
printf("%d,%d\n",lng,cnt);
cnt++;
}
text=realloc(text,cnt*sizeof(char));
print(text); /*prints all the lines*/
return 0;
}
The short answer is you can't directly allocate the memory unless you know how much to allocate.
However, there are various ways of determining how much you need to allocate.
There are two aspects to this. One is knowing how many strings you need to handle. There must be some defined way of knowing; either you're given a count, or there some specific pointer value (usually NULL) that tells you when you've reached the end.
To allocate the array of pointers to pointers, it is probably simplest to count the number of necessary pointers, and then allocate the space. Assuming a null terminated list:
size_t i;
for (i = 0; list[i] != NULL; i++)
;
char **space = malloc(i * sizeof(*space));
...error check allocation...
For each string, you can use strdup(); you assume that the strings are well-formed and hence null terminated. Or you can write your own analogue of strdup().
for (i = 0; list[i] != NULL; i++)
{
space[i] = strdup(list[i]);
...error check allocation...
}
An alternative approach scans the list of pointers once, but uses malloc() and realloc() multiple times. This is probably slower overall.
If you can't reliably tell when the list of strings ends or when the strings themselves end, you are hosed. Completely and utterly hosed.
C don't have strings. It just has pointers to (conventionally null-terminated) sequence of characters, and call them strings.
So just allocate first an array of pointers:
size_t nbelem= 10; /// number of elements
char **arr = calloc(nbelem, sizeof(char*));
You really want calloc because you really want that array to be cleared, so each pointer there is NULL. Of course, you test that calloc succeeded:
if (!arr) perror("calloc failed"), exit(EXIT_FAILURE);
At last, you fill some of the elements of the array:
arr[0] = "hello";
arr[1] = strdup("world");
(Don't forget to free the result of strdup and the result of calloc).
You could grow your array with realloc (but I don't advise doing that, because when realloc fails you could have lost your data). You could simply grow it by allocating a bigger copy, copy it inside, and redefine the pointer, e.g.
{ size_t newnbelem = 3*nbelem/2+10;
char**oldarr = arr;
char**newarr = calloc(newnbelem, sizeof(char*));
if (!newarr) perror("bigger calloc"), exit(EXIT_FAILURE);
memcpy (newarr, oldarr, sizeof(char*)*nbelem);
free (oldarr);
arr = newarr;
}
Don't forget to compile with gcc -Wall -g on Linux (improve your code till no warnings are given), and learn how to use the gdb debugger and the valgrind memory leak detector.
In c you can not allocate an array of string directly. You should stick with pointer to char array to use it as array of string. So use
char* strarr[length];
And to mentain the array of characters
You may take the approach somewhat like this:
Allocate a block of memory through a call to malloc()
Keep track of the size of input
When ever you need a increament in buffer size call realloc(ptr,size)

Resources