I am programming in C. I am using also a library to create tasks which can communicate among them via messages. The content of these messages must be the pointer to the data you want to exchange.
In my case I want to send an array so I am sending a pointer to the array. In the receiving task I can then access the different elements by increasing the pointer, but, is there a way to know how long the array was?
Thank you in advance.
No, there is no way to do this as arrays decay to pointers when passed to functions, thus all information regarding size is lost.
You can include another parameter to specify the array length
void func(int len, int arr[]);
You can mark the end of the array with a special value (perhaps like argv does)
You can put your array into a structure and pass that (and suffer the performance penalties) or pass the a pointer to the structure
struct args {
int arr[100];
};
If you decide to go the first route, you can use a nice feature of C99, even if it doesn't actually enforce that arr has at least len elements:
void func(int len, int arr[len]);
No. So consider something slightly different.
struct arrayinfo {
struct element *array;
int count;
};
Then you can pass a pointer to your struct arrayinfo type and your receiving task will know how many elements are in your array.
An alternative technique is to make your array and array of pointers. Make your array one element bigger than necessary and set the last element to NULL.
No, you can't. The compiler doesn't know what the pointer is pointing to. You either need to pass the length value along with the array or you can trick it by allocating extra memory in order to store the length value before the start of the array.
No, that is not possible unless you also send the size of the array or set a guardian value in the end of the array.
I suggest that you do not send the array directly but use a intermediary struct, like the following:
struct intermediary {
int *the_array; /* the pointer to the array */
size_t size; /* the array size */
};
In the message you send the struct, and not the array itself.
Couldn't you use some kind of sentry value at the end of the buffers where the messages are stored. That should be such a value that you won't find it anywhere in the message. Depending on the type of these message its possible that there is such a value: typically a negative number if your messages consists of positive integers, a "INF" or "BIG_INT" number, etc. Then, you must process your message just up to the sentry value. Something like this:
#include <stdlib.h>
#include <string.h>
#define N 100
#define ENDTAG -999999
void foo( int *arr ){
int i = 0;
while( arr[i] != ENDTAG ){
//do whatever
i++;
}
}
int main( void ){
int *arr = (int *) malloc( sizeof(int) * N );
//fill the array, no matter how.
// ...
//set the sentry value
arr[N-1] = ENDTAG;
foo( arr );
free( arr );
return 0;
}
It may sound to much simple, but I actually used something like that more than once. You must though be absolutely sure that you'll take some restricted types of messages.
Related
Say I want to loop over an array, so I used a basic for loop and accessed each element in it with the index but what happens if I don't know how long my array is?
#include <stdio.h>
#include <stdlib.h>
int main(){
int some_array[] = {2,3,5,7,2,17,2,5};
int i;
for (i=0;i<8;i++){
printf("%d\n",some_array[i]);
}
return 0;
}
This is just a simple example but if I don't know how big the array is, then how can I place a correct stopping argument in the loop?
In Python this is not needed since the StopIteration exception kicks in, but how can I implement it in C?
Just do like this:
for (i=0; i<sizeof(some_array)/sizeof(some_array[0]); i++){
printf("%d\n",some_array[i]);
}
But do beware. It will not work if you pass the array to a function. If you want to use it in a function, then write the function so that you also pass the size as argument. Like this:
void foo(int *arr, size_t size);
And call it like this:
foo(some_array, sizeof(some_array)/sizeof(some_array[0]));
But if you have a function that just take a pointer, there is absolutely no standard way to find out the size of it. You have to implement that yourself.
You have to know the size of the array. That's one of the most important rules of C programming. You, the programmer, are always responsible for knowing how large your array is. Sure, if you have a stack array or a static array, you can do this:
int array[size];
int size_of_array = sizeof array / sizeof *array;
for (int i = 0; i < size_of_array; i++) {
// do something with each array[i]
}
But as you can see, you needed the variable size in the first place. So what's the point of trying to discover the size if you were forced to know it already?
And if you try to pass this array to any function
some_function(array); /
you have to pass the size of the array too, because once the array is no longer in the same function that declared it, there is no mechanism to find its size again (unless the contents of the array indicate the size somehow, such as storing the number of elements in array[0] or using a sentinel to let you count the number of elements).
void some_function(int *array) {
/* Iterate over the elements until a sentinel is found.
* In this example, the sentinel is a negative number.
* Sentinels vary from application to application and
* implicitly tell you the size of the array.
*/
for (int i = 0; array[i] >= 0; i++) {
// do something with array[i]
}
}
And if it is a dynamically-allocated array, then you need to explicitly declare the number of elements anyway:
int size = 10;
int *array = malloc(sizeof *array * 10);
So, to summarize, you must always know the size of the array. There is no such thing in C as iterating over an array whose size you don't know.
You can use sizeof() to get the size of the array in bytes then divide the result by the size of the data type:
size_t n = sizeof(some_array)/sizeof(some_array[0]);
In general, you can calculate the size of the array with:
sizeof(ArrayName)/sizeof(ArrayType)
but this does not work with dynamically created arrays
I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)
as a beginner in C, I am struggling with an obscure problem and because I couldn't find a solution to this particular problem I want to ask you the following:
Currently I am trying to understand void pointers and their arithmetic operations. I attempted to write a generic function, which accepts a void pointer to an array, the length of the array and size of one element and splits the given array into two different parts (list1 and list2):
void split(void *array, int arrlen, int objsize)
{
// divide the arrlen and save the values
int len_list1 = arrlen / 2;
int len_list2 = arrlen - len_list1;
// Allocate memory for two temporary lists
void *list1 = (void*)malloc(objsize * len_list1);
void *list2 = (void*)malloc(objsize * len_list2);
if (list1 == NULL || list2 == NULL)
{
printf("[ERROR]!\n");
exit(-1);
}
// list1 gets initialized properly with int and char elements
memmove(list1, array, len_list1*objsize);
printf("list1:");
print_arr(list1, len_list1);
// memmove((char*)list2, (char*)array+list_1_length, list_2_length*objsize); (*)
memmove(list2, (int*)array+len_list1, len_list2*objsize);
printf("list2:");
print_arr(list2, len_list2);
}
My problem is the following:
If I give this function an int array it will work fine, but if I call split() with a char array as an argument, I have to...
memmove((char*)list2, (char*)array+list_1_length, list_2_length*objsize);
//memmove((int*)list2, (char*)array+list_1_length, list_2_length*objsize);
comment line (*) out, in order to have the same results. A solution certainly could be to write an if-else condition and test the objsize:
if (objsize == sizeof(int))
// move memory as in the 1st code snippet
else
// move memory with the (int*) cast
But with this solution I would also have to check other data types, so it would be very kind of you to give me a hint.
Thanks!
-matzui
memmove(list2, (int*)array+len_list1, len_list2*objsize);
Here you typecast array to an int *, and add len_list1 to it. But adding something to a pointer, means it will be multiplied with the size of one element of the datatype of that pointer. So if an int is 4 bytes, and you add 5 to an int * variable, it will move 20 bytes.
Because you know exactly how many bytes you want to move the pointer, you can cast is to char * (char = 1 byte), and add the number of bytes to it.
So instead of (int*)array+len_list1, you can use (char*)array+(len_list1*objsize)
A void pointer is just a word-sized dereferencable pointer that implies no particular data type. Thus, you cannot do pointer math with it. To do what you're trying to do, declare an appropriately typed pointer in your function, and then set its value equal to that of the parameter void pointer.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to find the sizeof(a pointer pointing to an array)
I know this to find the size of array = sizeof(arr)/sizeof(arr[0])
But I have to implement the following (It's just a demo):
demo.h
#ifndef __DEMO_H
#define __DEMO_H
void heap_sort(int *);
#endif
demo.c
void heap_sort(int *ptrA)
{
//implementing heap sort
But here it requires length of array
}
main.c
#include "demo.h"
int main(void)
{
int A[10];
heap_sort(A)
return 0;
}
FYI .. It's just a demo.. but here I have to implement it in some other scenarios in which there is restriction that "DON'T CHANGE ANYTHING IN HEADER FILE" which means i can't change the function signature . Then how to get the array length in demo.c For char it's easy to get by help of strlen() Isn't there anything similar to get the length of int,float double types
The only alternatives I see are:
use a special value as terminator (as strlen does).
use the Pascal trick, and place array length in the first element.
store the array size in a global external variable.
use a separate function.
E.g.:
int arraySize(int newSize)
{
static int arraySize = 0;
int oldSize;
oldSize = arraySize;
if (newSize)
arraySize = newSize;
return oldSize;
}
in main.c:
arraySize(10);
in demo.c:
arraylen = arraySize(0);
if you can't change the function signature, then maybe you could pass the size of the array in the first element.
A[0] = 10;
heap_sort(A);
Or mark the end of the array with some special value, but I don't like this one because you'd have to iterate the whole array to find the length and you need to make sure this value is not used in the array:
A[LENGTH-1] = END//some value;
void array_length(A) {
while (*A++ != END) {
length++;
}
}
This is just a solution for the restrictions you imposed, what I would normally do, is either pass the size of the array as a second argument, or use a struct for the array:
struct array_t {
int *data; //allocate this
int size;
};
Note: other horrible solutions include global variables.
Thinking of strlen() is going into the right direction.
Strings are character arrays with a '\0' as array termination, as last element.
You could take the same approach for any other type of array.
Just define one value as the value which indicates the last element in an array. Searching for this value then helps you to find the size of the array.
Update:
I like mux's idea of using the first element in an array.
Anyhow, using it to store the numbers of element in there might lead to problems in case the number of elements in the array is larger as what can be store in an array's element (a char array, for example, whould then be limited to 255 elements).
My approach on the other hand has the draw back that the value used as terminator to the array is not usable as real value in the arra itself.
The combining the former and the latter approaches, I propose to use the first element of the array to store the value which is used as terminator of the array.
The constraint seems a bit odd, but whatever.
Why not use a global variable to store the size.
I'm trying to create a function which takes an array as an argument, adds values to it (increasing its size if necessary) and returns the count of items.
So far I have:
int main(int argc, char** argv) {
int mSize = 10;
ent a[mSize];
int n;
n = addValues(a,mSize);
for(i=0;i<n;i++) {
//Print values from a
}
}
int addValues(ent *a, int mSize) {
int size = mSize;
i = 0;
while(....) { //Loop to add items to array
if(i>=size-1) {
size = size*2;
a = realloc(a, (size)*sizeof(ent));
}
//Add to array
i++;
}
return i;
}
This works if mSize is large enough to hold all the potential elements of the array, but if it needs resizing, I get a Segmentation Fault.
I have also tried:
int main(int argc, char** argv) {
...
ent *a;
...
}
int addValues(ent *a, int mSize) {
...
a = calloc(1, sizeof(ent);
//usual loop
...
}
To no avail.
I assume this is because when I call realloc, the copy of 'a' is pointed elsewhere - how is it possible to modify this so that 'a' always points to the same location?
Am I going about this correctly? Are there better ways to deal with dynamic structures in C? Should I be implementing a linked list to deal with these?
The main problem here is that you're trying to use realloc with a stack-allocated array. You have:
ent a[mSize];
That's automatic allocation on the stack. If you wanted to use realloc() on this later, you would create the array on the heap using malloc(), like this:
ent *a = (ent*)malloc(mSize * sizeof(ent));
So that the malloc library (and thus realloc(), etc.) knows about your array. From the looks of this, you may be confusing C99 variable-length arrays with true dynamic arrays, so be sure you understand the difference there before trying to fix this.
Really, though, if you are writing dynamic arrays in C, you should try to use OOP-ish design to encapsulate information about your arrays and hide it from the user. You want to consolidate information (e.g. pointer and size) about your array into a struct and operations (e.g. allocation, adding elements, removing elements, freeing, etc.) into special functions that work with your struct. So you might have:
typedef struct dynarray {
elt *data;
int size;
} dynarray;
And you might define some functions to work with dynarrays:
// malloc a dynarray and its data and returns a pointer to the dynarray
dynarray *dynarray_create();
// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);
// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);
// free the dynarray and its data.
void dynarray_free(dynarray *arr);
This way the user doesn't have to remember exactly how to allocate things or what size the array is currently. Hope that gets you started.
Try reworking it so a pointer to a pointer to the array is passed in, i.e. ent **a. Then you will be able to update the caller on the new location of the array.
this is a nice reason to use OOP. yes, you can do OOP on C, and it even looks nice if done correctly.
in this simple case you don't need inheritance nor polymorphism, just the encapsulation and methods concepts:
define a structure with a length and a data pointer. maybe an element size.
write getter/setter functions that operate on pointers to that struct.
the 'grow' function modifies the data pointer within the struct, but any struct pointer stays valid.
If you changed the variable declaration in main to be
ent *a = NULL;
the code would work more like you envisioned by not freeing a stack-allocated array. Setting a to NULL works because realloc treats this as if the user called malloc(size). Keep in mind that with this change, the prototype to addValue needs to change to
int addValues(ent **a, int mSize)
and that the code needs to handle the case of realloc failing. For example
while(....) { //Loop to add items to array
tmp = realloc(*a, size*sizeof(ent));
if (tmp) {
*a = tmp;
} else {
// allocation failed. either free *a or keep *a and
// return an error
}
//Add to array
i++;
}
I would expect that most implementations of realloc will internally allocate twice as much memory if the current buffer needs resizing making the original code's
size = size * 2;
unnecessary.
You are passing the array pointer by value. What this means is:
int main(int argc, char** argv) {
...
ent *a; // This...
...
}
int addValues(ent *a, int mSize) {
...
a = calloc(1, sizeof(ent); // ...is not the same as this
//usual loop
...
}
so changing the value of a in the addValues function does not change the value of a in main. To change the value of a in main you need to pass a reference to it to addValues. At the moment, the value of a is being copied and passed to addValues. To pass a reference to a use:
int addValues (int **a, int mSize)
and call it like:
int main(int argc, char** argv) {
...
ent *a; // This...
...
addValues (&a, mSize);
}
In the addValues, access the elements of a like this:
(*a)[element]
and reallocate the array like this:
(*a) = calloc (...);
Xahtep explains how your caller can deal with the fact that realloc() might move the array to a new location. As long as you do this, you should be fine.
realloc() might get expensive if you start working with large arrays. That's when it's time to start thinking of using other data structures -- a linked list, a binary tree, etc.
As stated you should pass pointer to pointer to update the pointer value.
But I would suggest redesign and avoid this technique, in most cases it can and should be avoided. Without knowing what exactly you trying to achieve it's hard to suggest alternative design, but I'm 99% sure that it's doable other way. And as Javier sad - think object oriented and you will always get better code.
Are you really required to use C? This would be a great application of C++'s "std::vector", which is precisely a dynamically-sized array (easily resizeble with a single call you don't have to write and debug yourself).