I have to dynamically increase a length of double array. I know, how to do it with char array, so I tried this:
int main() {
char * tmp = NULL;
for (int i = 1; i <= 4; i++) {
tmp = realloc(tmp, i * sizeof(char));
tmp[i] = 'i';
}
puts("char OK");
double * tmp1 = NULL;
for (int i = 1; i <= 4; i++) {
tmp1 = realloc(tmp1, i * sizeof(double));
tmp1[i] = 0;
}
return 0;
}
The first array works fine. But the second one crushes with message realloc(): invalid next size.
These are my 2 questions:
Why this way doesn't work in a double array?
How to dynamically increase the size of array of doubles?
UPD:
removed a typo
TL;DR: Both the snippets are wrong, the first one appears to work because of undefined behavior.
To elaborate, the problem is with your indexing logic. C uses a 0-based indexing. So, inside the loop which is staring the iteration from value of i as 1, by using
tmp[i] = .......
you're trying to access invalid memory, at this point, only access up to tmp[i-1] is valid.
You need to use tmp1[i-1] = 0;, and likewise.
That said,
Always check for the success of the memory allocator functions before using the returned pointers.
Never use the form
pointer = realloc (pointer, ......)
because, in case realloc call fails, you'll end up losing the original pointer, too.
Quoting C11, chapter ยง7.22.3.5
The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
and
[....] If memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Always use a temporary pointer variable to store the return value of realloc(),
check for the success of the call [not-null return value] and
then assign it back to the original variable, if needed.
Related
Hi I am quite new to C and I have a question about the behavior of array initialization using [] and malloc.
int main() {
int* pointer;
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
// expected 1 here, but got 99
printf("%d\n", pointer[1]);
return 0;
}
Why is the output 99? I thought the array is re-inited every loop, but it turns out using the same memory address. And if I use malloc to init the array instead, the result becomes 1 as expected.
Is there any way I could get result 1 without using malloc?
Your code is invalid as you access the variable which is out of the scope using the reference. It is undefined behaviour.
Every time you assign the i to the same element to the array. Pointer only references (points to) the first element of this array. So if you change the underlaying object the value you get using the reference will change as well. If your finger is pointing to the box of 5 apples and someone eats 2 apples, your finger will point to the box of 3 apples, not 5.
You need to make a copy of the object.
if(i == 1) {
pointer = malloc(sizeof(tmp));
memcpy(pointer, tmp, sizeof(tmp));
}
or break the loop (declaring it static or moving the tmp out of the for loop scope)
for(int i = 0; i < 100; i++) {
// Init the Array
static int tmp[2];
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
break;
}
}
The scope of the array tmp is the block scope of the for loop
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
That is in each iteration of the loop a new array tmp is created and ceases to be alive after exiting the block.
Thus the pointer pointer is invalid after the for loop. Dereferencing the pointer after the for loop invokes undefined behavior.
You have gotten the result 99 only because the array tmp was not being reallocated and the memory occupied by the array was not yet overwritten. So the last value stored in this extent of memory that is the value of i equal to 99 was outputted.
Even if you will declare the array tmp before the for loop then using the pointer pointer you will get as the output the value 99 that is the value last stored in the array.
You could write for example
int tmp[2] = { 0 };
int *pointer = tmp;
for(int i = 0; i < 100; i++) {
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
}
And the last value stored in the array (when i is equal to 99)
tmp[1] = i;
will be outputted in this call
printf("%d\n", pointer[1]);
Pay attention to that such an initialization with empty braces is invalid in C opposite to C++
int tmp[2] = {};
You need to write at least like
int tmp[2] = { 0 };
As we know pointer stores a memory address.
Here, I think when you give the command: pointer = tmp;,
the address of the array stored in 'tmp' is copied to the 'pointer'.
But when the loop of i = 1 gets completed, the array that you created in that particular loop and the pointer 'tmp' gets forgotten.
Then the loop for i=2 starts, 'tmp' and the array gets created again.
It happens again till the loop end.
I think that the program is storing tmp[1] at the same location every time due to which the data stored at that changes again and again.
So, when you give the command printf("%d\n", pointer[1]);, the data at that address get printed which is no longer equal to 1, it has changed.
The mistake is that we shared the address of 'tmp' with the 'pointer'.
But when we use malloc, we lock that memory means other programs can't use that memory. ( That's why we always need to free that memory to avoid memory leaks ).
It's the reason while using malloc you get output as 1 as your other commands can't touch that particular memory.
Solution:
If you want to solve the problem without malloc.
Initialise 'pointer' as an array to store data of 'tmp'.
use this code,
pointer[0] = tmp[0]; pointer[1] = tmp[1];
at place of
pointer = tmp;.
Now, you will not be copying addresses to 'pointer' but the data in the 'tmp'.
And if you have a big array with many values in it, just use it for loop.
solution image
Also, you will get the same problem if you do it like this, all because of copying only the address, you will be doing the same thing.
Maybe you can relate,same problem image
Thanks.
I am writing a code and i hope this summon my problem.
Any help is appreciated>
I created an array by:
intermediateBinCounts = (int *)malloc(bin_count * thread_count * sizeof(int));
and want it to increment value in another function:
for(int i=privateStartingIndex; i<privateEndingIndex; i++){
int returnedBinIndex = findBin(data[i]);
int intermBinCountIndex = (threadIndex*bin_count)+returnedBinIndex;
intermediateBinCounts[intermBinCountIndex]++;
printf("\nthis is value %d\n", intermediateBinCounts[intermBinCountIndex]);
}
intermBinCountIndex is integer which is returned from the function and their value in my case are among 0, 1, 2, 3 only.
but my printf is returning:
this is value -1163005938
this is value -1163005937
this is value -1163005938
I don't know if my question is able to articulate my issue if it is not able to please let me know so that I could edit it again my best.
I want that intermediateBinCounts to be initialized to zero and increment the value at that index which value is returned from the function call i.e findBin.
I want that intermediateBinCounts to be initialized to zero
Well, you don't want that. intermediateBinCounts is a pointer and you want to set it to the value returned by malloc.
What you want to set to zero is the memory that intermediateBinCounts points to!
You can use a simple loop after the malloc- like:
int * intermediateBinCounts = malloc(bin_count * thread_count * sizeof(int));
for (int i=0; i < bin_count * thread_count; ++i)
{
intermediateBinCounts[i] = 0;
}
or use calloc instead of malloc as calloc zero initialize the allocated memory:
int* intermediateBinCounts = calloc(bin_count * thread_count, sizeof(int));
This declares a pointer to int, without already defining it, this is for headers
(though doing this implies global variables which many users recommend against):
extern int* pointer;
This defines that pointer, without initialising it; this is for exactly one code file:
int* pointer;
This defines and initialises the pointer; use it instead of above:
int* pointer=NULL;
This allocates some memory to the pointer:
pointer = malloc(sizeof(int));
This initialises the allocated memory:
*pointer=0;
This uses the initialised value pointed to by the pointer and increments it; doing this before above means undefined behaviour and would explain your unexpected values:
*pointer = *pointer +1;
Please check your code for what you are actually doing when.
Most likely you did not do the initialising.
My problem is that i am not sure how to allocate memory properly. I have researched it but to no avail. Some help regarding malloc would be great.
int main(int argc, char *argv[]) {
int i, a[5000], c = 1, m, n, input;
scanf("%d", &input);
for (i = 0; i <= 9999; i += 2) {
a[c] = i;
c++;
}
for (n = 2; n < 1118; n++) {
for (m = a[n]; m < a[5000]; m++) {
a[m] = a[m+1];
}
}
printf("%d", a[input]);
free (*a);
return 0;
}
'a' is allocated on stack therefore no need to free it.
You only need to free variables allocated by *alloc family of functions.
First of all, C arrays have 0-based indexing. By setting the intial value of c to 1 and then using as index inside the loop, you're going off-by-one. This invokes undefined behavior.
After that, you don't need to do free (*a);, a is an array, not a pointer returned by a memory allocator functions, malloc() or family.
That said, in this code, *a does not give you a pointer, at all, it is same as a[0] which is of type int.
Finally, without any bound checking from user supplied value of input, using a[input] may very well be accessing out of bound memory, causing UB.
FWIW, passing a pointer to free() which is not returned previously by malloc() and family also invokes undefined behavior.
malloc takes one argument - the number of bytes to allocate. It returns a void pointer (which is a pointer to a section of memory that can hold any data type).
Here's an example.
int *array = malloc(sizeof(int) * 10);
This allocates a 10-element array of integers. Note it leaves your data uninitialized, so the contents of the array are undefined. There's a function called calloc that does initialize it to zeros.
Also, a style tip. You might try to cast the result of a malloc call to a pointer for the type of data you will store in it (for example, int *array = (int *)malloc(sizeof(int) * 10);. This is frowned upon by C programmers for reasons explained in this post.
The goal is to read in 105 words in from a file and assign them to an array. The array is initialized to
char **array = (char**)malloc(*capacity * sizeof(char*));
where capacity is set to 50.
I'm trying to make it so this function is called when 50 words have been read in and the 51st is being ready to.
The initial allocation for the array should be space for 50 pointers. If the array ever gets full (i.e., wordCount equals current capacity), and there's a word to insert, I will double the capacity of the array (i.e., malloc a new array of twice the current size, copy the strings over into the front half of the newly allocated array, and free the space used by the old array. I am not allowed to use realloc. I would just like help fixing the way to do this using my method. Please do not suggest alternate methods.
So I keep getting a segmentation fault and I don't understand why. Any advice?
int doubleArraySize(char ***array, int count, int *capacity){
char **temp = (char**)malloc(*capacity * sizeof(char*));
if (temp = NULL){
return -1;
}
int i = 0;
while(i<count){
temp[i] = *array[i];
i++;
}
i = 0;
while(i<count){
free(*array[i]);
i++;
}
free(*array);
*array = temp;
return 0;
}
And yes I am not allowed to use realloc. I was specifically told to create a new array of double the size and copy the elements to the first half then free the old one. Also in a debugger i am using, it says the problem lies in the line
temp[i] = *array[i];
but i have no idea why. Thank you in advanced!
Change *array[i] to (*array)[i] in temp[i] = *array[i];.
The subscript operator [] has higher precedence than the dereference operator *, thus (*array)[i] designates the i-th element of a char* array, while *array[i] is dereferencing the i-th element of a char** array. According to the logic of your program, the former is what you really want, so the parentheses can't be omitted.
And you shouldn't free any of the individual (*array)[i], since you actually store them in the newly allocated array. Just free(*array) is enough.
First of all, don't cast the result of malloc. It has no benefit and can cause bugs if you forget to include the header stdlib.h. Read this for details - Do I cast the result of malloc?
Now, there is a problem with the statement you use to copy the old array into the new one -
temp[i] = *array[i];
The array subscript operator [] has higher precedence than the dereference operator *. Therefore the above is the same as -
temp[i] = *(array[i]);
array is of type char *** and points to an array of objects of type char **. array[i] evaluates to *(array + i) which does illegal memory access invoking undefined behaviour. Therefore, you should change the statement to
temp[i] = (*array)[i];
which means dereference array first and then get the ith element in the buffer pointed to by array. I suggest using the standard library function memcpy to copy the old array into the new one. Also, to free a block of dynamically allocated buffer, you just need to pass the base address of the buffer and the entire block is freed.
#include <string.h>
#include <stdlib.h>
int doubleArraySize(char ***array, int count, int *capacity) {
char **temp = malloc(*capacity * sizeof *temp);
if(temp = NULL){
return -1;
}
memcpy(temp, *array, count * sizeof **array);
free(*array);
*array = temp;
return 0;
}
I am supposed to follow the following criteria:
Implement function answer4 (pointer parameter and n):
Prepare an array of student_record using malloc() of n items.
Duplicate the student record from the parameter to the array n
times.
Return the array.
And I came with the code below, but it's obviously not correct. What's the correct way to implement this?
student_record *answer4(student_record* p, unsigned int n)
{
int i;
student_record* q = malloc(sizeof(student_record)*n);
for(i = 0; i < n ; i++){
q[i] = p[i];
}
free(q);
return q;
};
p = malloc(sizeof(student_record)*n);
This is problematic: you're overwriting the p input argument, so you can't reference the data you were handed after that line.
Which means that your inner loop reads initialized data.
This:
return a;
is problematic too - it would return a pointer to a local variable, and that's not good - that pointer becomes invalid as soon as the function returns.
What you need is something like:
student_record* ret = malloc(...);
for (int i=...) {
// copy p[i] to ret[i]
}
return ret;
1) You reassigned p, the array you were suppose to copy, by calling malloc().
2) You can't return the address of a local stack variable (a). Change a to a pointer, malloc it to the size of p, and copy p into. Malloc'd memory is heap memory, and so you can return such an address.
a[] is a local automatic array. Once you return from the function, it is erased from memory, so the calling function can't use the array you returned.
What you probably wanted to do is to malloc a new array (ie, not p), into which you should assign the duplicates and return its values w/o freeing the malloced memory.
Try to use better names, it might help in avoiding the obvious mix-up errors you have in your code.
For instance, start the function with:
student_record * answer4(const student_record *template, size_t n)
{
...
}
It also makes the code clearer. Note that I added const to make it clearer that the first argument is input-only, and made the type of the second one size_t which is good when dealing with "counts" and sizes of things.
The code in this question is evolving quite quickly but at the time of this answer it contains these two lines:
free(q);
return q;
This is guaranteed to be wrong - after the call to free its argument points to invalid memory and anything could happen subsequently upon using the value of q. i.e. you're returning an invalid pointer. Since you're returning q, don't free it yet! It becomes a "caller-owned" variable and it becomes the caller's responsibility to free it.
student_record* answer4(student_record* p, unsigned int n)
{
uint8_t *data, *pos;
size_t size = sizeof(student_record);
data = malloc(size*n);
pos = data;
for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
memcpy(pos,p,size);
return (student_record *)data;
};
You may do like this.
This compiles and, I think, does what you want:
student_record *answer4(const student_record *const p, const unsigned int n)
{
unsigned int i;
student_record *const a = malloc(sizeof(student_record)*n);
for(i = 0; i < n; ++i)
{
a[i] = p[i];
}
return a;
};
Several points:
The existing array is identified as p. You want to copy from it. You probably do not want to free it (to free it is probably the caller's job).
The new array is a. You want to copy to it. The function cannot free it, because the caller will need it. Therefore, the caller must take the responsibility to free it, once the caller has done with it.
The array has n elements, indexed 0 through n-1. The usual way to express the upper bound on the index thus is i < n.
The consts I have added are not required, but well-written code will probably include them.
Altought, there are previous GOOD answers to this question, I couldn't avoid added my own. Since I got pascal programming in Collegue, I am used to do this, in C related programming languages:
void* AnyFunction(int AnyParameter)
{
void* Result = NULL;
DoSomethingWith(Result);
return Result;
}
This, helps me to easy debug, and avoid bugs like the one mention by #ysap, related to pointers.
Something important to remember, is that the question mention to return a SINGLE pointer, this a common caveat, because a pointer, can be used to address a single item, or a consecutive array !!!
This question suggests to use an array as A CONCEPT, with pointers, NOT USING ARRAY SYNTAX.
// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
// empty result variable for this function:
student_record* Result = NULL;
// the result will allocate a conceptual array, even if it is a single pointer:
student_record* Result = malloc(sizeof(student_record)*n);
// a copy of the destination result, will move for each item
student_record* dest = Result;
int i;
for(i = 0; i < n ; i++){
// copy contents, not address:
*dest = *student;
// move to next item of "Result"
dest++;
}
// the data referenced by "Result", was changed using "dest"
return Result;
} // student_record* answer4(...)
Check that, there is not subscript operator here, because of addressing with pointers.
Please, don't start a pascal v.s. c flame war, this is just a suggestion.