I am trying to print a dynamic array, but I am having trouble with the bounds for the array.
For a simple example, lets say I'm trying to loop through an array of ints. How can I get the size of the array? I was trying to divide the size of the array by the size of the type like this sizeof(list)/sizeof(int) but that was not working correctly. I understand that I was trying to divide the size of the pointer by the type.
int *list
// Populate list
int i;
for(i = 0; i < ????; i++)
printf("%d", list[i]);
With dynamic arrays you need to maintain a pointer to the beginning address of the array and a value that holds the number of elements in that array. There may be other ways, but this is the easiest way I can think of.
sizeof(list) will also return 4 because the compiler is calculating the size of an integer pointer, not the size of your array, and this will always be four bytes (depending on your compiler).
YOU should know the size of the array, as you are who allocated it.
sizeof is an operator, which means it does its job at compile time. It will give you the size of an object, but not the length of an array.
So, sizeof(int*) is 32/62-bit depending on architecture.
Take a look at std::vector.
There is no standardized method to get the size of allocated memory block. You should keep size of list in unsigned listSize like this:
int *list;
unsigned listSize;
list = malloc(x * sizeof(int));
listSize = x;
If you are coding in C++, then it is better to use STL container like std::vector<>
As you wrote, you really did tried to divide the size of a pointer since list is declared as a pointer, and not an array. In those cases, you should keep the size of the list during the build of it, or finish the list with a special cell, say NULL, or anything else that will not be used in the array.
Seeing some of the inapropriate links to C++ tools for a C question, here is an answer for modern C.
Your ideas of what went wrong are quite correct, as you did it you only have a pointer, no size information about the allocation.
Modern C has variable length arrays (VLA) that you can either use directly or via malloc. Direcly:
int list[n];
and then your idea with the sizeof works out of the box, even if you changed your n in the mean time. This use is to be taken with a bit of care, since this is allocated on the stack. You shouldn't reserve too much, here. For a use with malloc:
int (list*)[n] = malloc(*list);
Then you'd have to adapt your code a bit basically putting a (*list) everywhere you had just list.
If by size you mean the number of elements then you could keep it in a counter that gets a ++ each time you push an element or if you dont mind the lost cycles you could make a function that gets a copy of the pointer to the first location, runs thru the list keeping a counter until it finds a k.next==null. or you could keep a list that as a next and a prev that way you wouldnt care if you lost the beginning.
Related
include <stdio.h>
int main() {
int num = 10;
int arr[num];
for(int i = 0; i < num; i++){
arr[num] = i+1;
}
}
Some colleague of mine says that this code is not correct and that it is illegal. However, when I am running it, it is working without any errors. And he does not know how to explain why it is working and why I should not code like this. Can you please help me. I am a beginner and I want to learn C.
If you want to dynamically allocate an array of length n ints, you'll need to use either malloc or calloc. Calloc is preferred for array allocation because it has a built in multiplication overflow check.
int num = 10;
int *arr = calloc(num, sizeof(*arr));
//Do whatever you need to do with arr
free(arr);
arr = NULL;
Whenever you allocate memory with malloc or calloc, always remember to free it afterwards, then set the pointer to NULL in order to prevent any accidental, future references, as well as to prevent a double free.
While not necessarily illegal, this code won't do what you intend. When you declare an array, you declare the number of items you want to store, in this instance num. So when you declare num = 10 and arr[num] you get an array that can hold 10 integers. C arrays are indexed from 0, so the indices are 0-9, not 1-10. This is probably what they mean by illegal. Since you are writing to arr[num] or arr[10], you are attempting to use memory beyond the memory allocated for the array.
Additionally, if I understand the intent of the program correctly, you want to fill in the array with the numbers 1-10. To do this, you'd need to access each index individually. You're almost there, the only problem being arr[num] = i + 1;. As mentioned before, it is beyond the end of the array. However, you should probably be using i as your index, so arr[i], because this will access each index, 0-9.
Are you learning C or C++?
Your colleague meant that in that code of yours you are doing something different from what you wanted. It's working because of some additional factors. Because C/C++ standards are evolving and so do compilers as well. Let me show you.
Static array
When you a beginner, it's generally advised to stick to the concept that "a typed array of the compilation-given size" is int arr[N], where N is a constant. You allocate it on the stack and you don't manage it's memory.
In C++11 you can use a constexpr (constant expression), but is still not an arbitrary variable.
In C++14 you can use a "simple expression" for size, but you shouldn't try a lot of it before getting the array concept beforehand. Also, GCC compiler provides an extension to support variable sized arrays, it could be an explanation of "why the code is working at all".
Notice: variable sized arrays are not the same as dynamic arrays. They are not that static arrays from the first chapter of a C/C++ guide book as well.
There also exists a modern approach – std::array<int, 10> but once again, don't start with it.
Dynamic array
When you need to create an array in runtime everything changes. First of all, you allocate it on the heap and either you mange it's memory yourself (if you do not, you get a memory leak, a Pure C way) or use special C++ classes like std::vector. Once again, vectors should be used after getting to know Pure C arrays.
Your colleague must have been meaning something like that:
int* arr = new int[some_variable]; // this is dynamic array allocation
delete[] arr; // in modern C/C++ you can write "delete arr;" as well
So, your compiler made it work in this exact case, but you definitely should not rely on the approach you've tried. It's not an array allocation at all.
TL;DR:
In C++ variable length arrays are not legal
g++ compiler allows variable length arrays, because C99 allows them
Remember that C and C++ are two different languages
The piece of code from the question seems to be not doing what you'd wanted it to do
As others mentioned, it should be arr[i] = i + 1 instead, you are assigning to the same array item all the time otherwise
I have a function that will add a new position to an array by reallocating new memory every time it is called.
The problem is that, for each call I need it to add one position to the array, starting from 1 at first call, but I understand that I have to mallocate before reallocating.
So my question is, can I initially do something like p = malloc(0) and then reallocate for example using p = (int *)realloc(p,sizeof(int)) inside my function? p is declared as int *p.
Maybe with a different syntax?
Of course I could make a condition in my function that would mallocate if memory hasn't been allocated before and reallocate if it has, but I am looking for a better way.
And the second problem I have is... Once reallocated more positions, I want to know the size of the array.
I know that if, for example, I declare an array a[10], the number of elements would be defined by sizeof(a)/sizeof(a[0]), but for some reason that doesn't work with arrays declared as pointers and then reallocated.
Any advice?
You could initialize your pointer to NULL, so that the first time you call realloc(yourPointer, yourSize), it will return the same value as malloc(yourSize).
For your second problem, you could use a struct that contains your pointer and a count member.
struct MyIntVector {
int * ptr;
size_t count;
}
Then you probably will want to define wrapper functions for malloc, realloc, and free (where you could reset ptr to NULL), that takes your struct as one of the parameters, and updates the struct as needed.
If you want to optimize this for pushing 1 element at a time, you could add a allocatedCount member, and only realloc if count == allocatedCount, with a new allocatedCount equals (for example) twice the old allocatedCount.
You should implement this in a MyIntVector_Push(MyIntVector *, int ) function.
You will then have a simplified c version of c++ std::vector<int> (but without automatic deallocation when the object goes out of scope).
As ThreeStarProgrammer57 said just use realloc.
realloc(NULL, nr_of_bytes) is equivalent to malloc(nr_of_bytes)
so
p = realloc(p, your_new_size)
will work just fine the first time if p is initialized to NULL. But be sure to pass the number of bytes you need after resizing, not the additional space that you want, as you have written your question.
As regarding the size, you have to keep track of it. That's the way C was designed.
I'm trying to get the number of elements in an array of structs so I can pass it into another function. Struct:
struct info{
char string1[30];
float float1;
int int1;
char string2[30];
};
Section I'm trying to run:
void function1(){
struct info* temp = build();
printf("flag: %lu %lu %lu\n", sizeof(temp), sizeof(temp[0]), sizeof(temp)/sizeof(temp[0]));
sortFloat(temp, sizeof(temp)/sizeof(temp[0]), 1);
free(temp);
}
build() returns an array of structs after reading in data from a file where each line will be a struct in the array. I'm having trouble passing the size of the array into sortFloat(). The print line returns
flag: 8 72 0
when there are only two lines in the data file. Hard coding that argument as 2 makes the whole program work correctly. Why is this method of counting the elements of the array of structs not?
sizeof(temp)
will not evaluate to the number of elements in the array. It will evaluate to just the size of the pointer.
If you need the size of the array, you can do this:
Change the signature of build to:
struct info* build(int* sizePtr);
Make sure that sizePtr is appropriately set in the implementation.
Then, call it using:
int size;
struct info* temp = build(&size);
What you are thinking of as an array is more precisely just a pointer to the first element. How many elements follow the first element cannot be known to function1(). Only the function build() knows how many elements were read and how much memory was dynamically allocated to store those elements.
The only solution is to get the build() function to also pass back the number of elements read from the file. One way to do this is to send the address of an int variable to build(int *countp) and have build(int *countp) store the count into this int using either ++*countp; as it reads each element or *countp = n; where n is a different variable in which build(...) maintains the count.
Because temp is not an array. It is a pointer. So calling sizeof on it will return the size of the pointer.
It might be hard to understand, but in C, arrays (real arrays, not pointers) are best regarded as value types that are quite tricky to pass around by value. Arrays are not pointers and pointers are not arrays.
sizeof is an operator for determining the size of memory occupied by a value. That is why, when applied to an array, it returns the size of the array, and when applied to a pointer - just the size of the pointer.
What you're creating and returning from build() is most likely a dynamically-allocated (via malloc or friends) buffer of memory. In this case, it was never a real array to begin with! It is just a pointer to a chunk of memory on the heap. This chunk of memory is not one value, and its size cannot be determined using sizeof like that. So you've got no choice but to count the number of allocated structs and get that information to the caller.
When shall i use malloc instead of normal array definition in C?
I can't understand the difference between:
int a[3]={1,2,3}
int array[sizeof(a)/sizeof(int)]
and:
array=(int *)malloc(sizeof(int)*sizeof(a));
In general, use malloc() when:
the array is too large to be placed on the stack
the lifetime of the array must outlive the scope where it is created
Otherwise, use a stack allocated array.
int a[3]={1,2,3}
int array[sizeof(a)/sizeof(int)]
If used as local variables, both a and array would be allocated on the stack. Stack allocation has its pros and cons:
pro: it is very fast - it only takes one register subtraction operation to create stack space and one register addition operation to reclaim it back
con: stack size is usually limited (and also fixed at link time on Windows)
In both cases the number of elements in each arrays is a compile-time constant: 3 is obviously a constant while sizeof(a)/sizeof(int) can be computed at compile time since both the size of a and the size of int are known at the time when array is declared.
When the number of elements is known only at run-time or when the size of the array is too large to safely fit into the stack space, then heap allocation is used:
array=(int *)malloc(sizeof(int)*sizeof(a));
As already pointed out, this should be malloc(sizeof(a)) since the size of a is already the number of bytes it takes and not the number of elements and thus additional multiplication by sizeof(int) is not necessary.
Heap allocaiton and deallocation is relatively expensive operation (compared to stack allocation) and this should be carefully weighted against the benefits it provides, e.g. in code that gets called multitude of times in tight loops.
Modern C compilers support the C99 version of the C standard that introduces the so-called variable-length arrays (or VLAs) which resemble similar features available in other languages. VLA's size is specified at run-time, like in this case:
void func(int n)
{
int array[n];
...
}
array is still allocated on the stack as if memory for the array has been allocated by a call to alloca(3).
You definately have to use malloc() if you don't want your array to have a fixed size. Depending on what you are trying to do, you might not know in advance how much memory you are going to need for a given task or you might need to dynamically resize your array at runtime, for example you might enlarge it if there is more data coming in. The latter can be done using realloc() without data loss.
Instead of initializing an array as in your original post you should just initialize a pointer to integer like.
int* array; // this variable will just contain the addresse of an integer sized block in memory
int length = 5; // how long do you want your array to be;
array = malloc(sizeof(int) * length); // this allocates the memory needed for your array and sets the pointer created above to first block of that region;
int newLength = 10;
array = realloc(array, sizeof(int) * newLength); // increase the size of the array while leaving its contents intact;
Your code is very strange.
The answer to the question in the title is probably something like "use automatically allocated arrays when you need quite small amounts of data that is short-lived, heap allocations using malloc() for anything else". But it's hard to pin down an exact answer, it depends a lot on the situation.
Not sure why you are showing first an array, then another array that tries to compute its length from the first one, and finally a malloc() call which tries do to the same.
Normally you have an idea of the number of desired elements, rather than an existing array whose size you want to mimic.
The second line is better as:
int array[sizeof a / sizeof *a];
No need to repeat a dependency on the type of a, the above will define array as an array of int with the same number of elements as the array a. Note that this only works if a is indeed an array.
Also, the third line should probably be:
array = malloc(sizeof a);
No need to get too clever (especially since you got it wrong) about the sizeof argument, and no need to cast malloc()'s return value.
I'm making a dynamic array with int* data type using malloc(). But the problems is, how to know end of array?
There no an equivalent to \0 for int* data type,so, how to do this? Pass size as out parameter of function?
C doesn't manage array lengths, as some other languages do.
you might consider a structure for this:
typedef struct t_thing {
int* things;
size_t count;
} t_thing;
in use:
t_thing t = { (int*)malloc(sizeof(int) * n), n };
There is no "official" equivalent to \0 for integers, but you can certainly use your own value. For example, if your integers represent distances then you can use -1 (not a valid distance) as a sentinel value to indicate the end of the array.
If your integer array can reasonably contain any int value, then you can pass back the size of the allocated array with an additional parameter to your function.
You can use NULL as an end value. You can add an integer to a struct with the array that tracks the number of entries. Or you can track the size separately. You can do it however you want.
C does not know where is the end of your dynamic array. you should remember the size that you allocate for the array.
when u allocate memory with malloc, the number of bytes allocated is stored just before the start of the 'malloc'ated memory. if you know the size, you know the end as well!
This is explained in the bible of C, the K&R book. Wish I could give you the page number as well, but you'll know it when u see it.