Based on This Question Calculate Length of Array in C by Using Function i really need an explanation.
Let's say we have an Array like this:
int arr[] = {1,2,3};
here arr has the length 3, so passing into a Function will decay to Pointer and we lose track of its Length.
What happens if we Null terminate this array using '\0' like this:
int arr[] = {1,2,3,'\0'};
And pass it to a function like this:
void foo(int *arr){
int length = 0;
while(arr[length] != '\0'){
length++;
}
printf("Length = %d\n",length);
}
Is this ok?
I wrote the following code:
#include<stdio.h>
void foo(int *arr);
int main(void){
int arr1[] = {10,'\0'};
int arr2[] = {12,44,'\0'};
int arr3[] = {87,1,71,'\0'};
int arr4[] = {120,15,31,82,'\0'};
int arr5[] = {28,49,16,33,11,'\0'};
int arr6[] = {19,184,90,52,38,77,'\0'};
int arr7[] = {2,17,23,41,61,78,104,'\0'};
int arr8[] = {16,92,11,35,52,118,79,44,'\0'};
int arr9[] = {20,44,33,75,49,36,9,2,11,'\0'};
int arr10[] = {92,145,24,61,99,145,172,255,300,10,'\0'};
foo(arr1);
foo(arr2);
foo(arr3);
foo(arr4);
foo(arr5);
foo(arr6);
foo(arr7);
foo(arr8);
foo(arr9);
foo(arr10);
return 0;
}
void foo(int *arr){
int length = 0;
while(arr[length] != '\0'){
length++;
}
printf("Length = %d\n",length);
}
And i got the following Output:
Length = 1
Length = 2
Length = 3
Length = 4
Length = 5
Length = 6
Length = 7
Length = 8
Length = 9
Length = 10
Which prints the Length of all 10 arrays.
Now I'm confused here, because as far of my concern, as I read in some books, there is no way to make it work.
Why foo prints the length of all arrays?
It is illegal to use something like int arr[] = {1,2,3,'\0'}; ?
I know that if the Array has a 0 inside like this int arr[] = {1,2,0,3,4}; the length will be 2, but this is not my question.
This is how C-strings mark their end and length. And as they're just char arrays, naturally you can apply the same to other types of arrays as well.
Just remember that calculating the length of such an array through a pointer has a linear time complexity.
It is illegal to use something like int arr[] = {1,2,3,'\0'}; ?
No. It's perfectly legal. '\0' is an int which is same as 0. It's no different to using any number as marker to identify the end of the array. For example, you can use -1 if you array is going to contain only positive number. So your approach is valid.
The reason you wouldn't usually see in practice it's kind of needless to iterate over an array when you can simply pass it as an extra argument, which is easily understandable from maintenance point of view.
int arr[1024];
size_t len = sizeof arr/sizeof a[0];
func(arr, len);
void func(int *a, size_t length) {
}
Compare this with your approach.
Also, the size is calculated at compile-time whereas in your approach you have iterate over the array. Choosing the right sentinel could become difficult ( o or -1 or whatever) if it's also needed to be an element of the array.
Sidenote: '\0' is really 0 here, as your store ints.
You're using a sentinel. C-style strings have been using this method for decades to mark where the string finishes. It has the same benefits, but it also has the same drawbacks.
As long as you maintain the invariant that the sentinel occours only at the last place of the array you'll be able to get the length of the array. In O(N) time, as you have to traverse the sequence.
Note that you can shrink the sequence by terminating it earlier with a sentinel:
1 2 3 4 0 //
1 2 3 0 * // * as in: anything
But as soon as you do this, you cannot known the size of the array anymore. Even though you could technically append an extra element, a function without knowing the context cannot safely do this. In essence, you know the size of the sequence, but you don't known the size of the array anymore.
If you need a method to use to allow you to carry the array length with the array then try using one of these approaches.
Store the length in the start of the array
So (ideally) array[0], the first element would be a length.
The catch is that that only works if your array has a suitable type and the length fit in that type. You can in principle use union to define an element large enough to hold different types of data, including the length, but it's potentially wasteful.
Maintain a structure to store the array length and a pointer to the array data.
This is something like :
struct arrayinfo_s {
int length ;
char *data ;
};
char name[1000] ;
struct arrayinfo a ;
a.length = sizeof(name) ;
a.data = name ;
myfunc( &arrayinfo ) ;
There are many variations on this possible.
The "standard" convention.
As someone already mentioned, it is typical to track the array length and pass it as a separate parameter to the function.
myfunc( array, length ) ;
If array is a fixed size declared like e.g. int nums[100] ; then you can use sizeof(nums) if the variable was declared in the same function as you used sizeof() or globally.
There is also a variation on this for allowing a function to return an array of unknown length. Typically you would do something like returning a point to the array, but pass a parameter that is a pointer to some integer type to store the length of the new array in.
char *newstuff( int *newlength )
{
char *p = NULL ;
p = malloc( 102 ) ;
if( p == NULL )
{
*length = 102 ;
return p ;
}
else
{
*length = 0 ;
return NULL ;
}
}
Related
This question already has answers here:
C sizeof a passed array [duplicate]
(7 answers)
Closed 2 years ago.
Is there a way I could get the length of an array inside a function? I need to find the size of an array, however it is defined in the main function and I cannot pass the array size as an argument as I cannot change the main function. So is there any way to find it through the function?
The array's max size is set to be roughly 100, however the actual input will be anywhere between size 1 - 20. So I can't really take the max size approach either.
No, arrays always decay to pointers when passing into functions so you must pass the length in if you want the function to know the size. With some preconditions you have multiple ways to do that without an additional parameter:
Add a null/zero/whatever special parameter at the last, similar to a null-terminated char array. This is only possible if you really know there's a unique value that never appears in the value list to put at the final position. This method is actually very common in Linux system calls, for example the exec family
char *args[] = { "Hello", "C", "Programming", NULL /* ends the array */ };
execv("./hello", args);
Add a length prefix at the beginning
void my_function(int array[])
{
int length = array[0];
int* data = &array[1];
// operate on data[];
}
int my_data[LENGTH + 1] = { LENGTH, /* values */ };
my_function(my_data);
Pascal also uses length-prefixed string, so its string is limited to only 255 characters with a 1-byte length. But this can be fixed by using a bigger length
A variation of this is BSTR in Windows where the pointer points to the actual data instead of start of the struct
typedef struct MY_ARRAY
{
int32_t length;
my_type* data; // array of the desired type
} my_array;
void my_function(my_type array[])
{
int length;
memcpy(&length, (char*)array - sizeof(int32_t), sizeof(int32_t));
// operate on array[];
}
my_type data_list[] = { /* some data */ };
my_array my_data = { LENGTH, data_list };
my_function(my_data.data);
if the function is declared for example like
void f( T a[] );
where T is some type specifier then the function deals with a pointer to the type T. That is the above declaration is equivalent to the following declaration
void f( T *a );
and the both declare the same one function.
So the only way to calculate the number of actual elements in the array pointed to by the pointer is to introduce a sentinel value that will differ from values of actual elements of the array.
For example a character array can have such a sentinel value like '\0' that is when a character array contains a string.
An array of strings can have as a sentinel value either an empty string "" or depending on how it is declared (for example as an array of element type char *) the sentinel value can be NULL.
For integer arrays you have yourself to select an appropriate value as a sentinel value. For example if actual elements are non-negative then the sentinel value can be set to -1.
You could include a for loop with a counter to see how many variables there are before the the next line.
int counter(int array[100]) {
int counter = -1;
for (i = 0; array != '\0'; i++) {
counter = counter + 1;
}
return counter;
}
and then in the main section
int arraysize = counter();
I want to filter an strings array passed in, something like this:
char **
filter_vids(char **vids, size_t n) {
int i;
int count = 0;
char ** filted = malloc(n * sizeof(char *));
for(i = 0; i < n; i++){
filted[i] = (char*)malloc(50 * sizeof(char));
}
for(i = 0; i < n; i++) {
if(some_filter(vids[i])) {
strcpy(filted[count++], vids[i]);
printf("in filter:%s\n", vids[i]);
}
}
return filted;
}
But the caller may not known the length of return array, it's extractly the counter variable, so what's the best practice of returning an array while telling him the right length of array?
such as
char **
filter_vids(char **vids, size_t n, int *output_length)
It's the best practice of using output_length?
I edit this function to this, as your suggestions:
char **
filter_vids(char **vids, size_t n) {
int i;
int count = 0;
char ** filted = malloc((n + 1) * sizeof(char *));
for(i = 0; i < n; i++) {
if(vids[i][0] <= 'f') {
filted[count++] = strdup(vids[i]);
}
}
filted[count] = NULL;
return filted;
}
To pass a pointer to an integer length variable whose value is then set in the function is certainly a good way. As Malcolm said, it is also general and can be used for sets of values which do not have an "invalid" member.
In the case of pointers with their invalid null pointer value one can mark the end of valid entries with a null pointer. For example, the array of string pointers which the C run time uses to pass command line arguments to main is thus terminated.
Which method to choose depends a little on how the caller wants to use the resulting array. If it is processed sequentially, a (while *p){ ..; ++p; } feels idiomatic. If, on the other hand, you need random access and must perform the equivalent of a strlen before you can do anything with the array, then it is probably better to return the length via a pointed-to length variable right away.
Two remarks:
First, note the difference between
a valid pointer to an empty string (if somebody called, let's say, myProg par1 "" par2, argv[2] could be a valid pointer to a zero byte);
and a null pointer which is pointing nowhere; in the example, argv[4] would be the null pointer, indicating the end of the argument list.
Second, You malloc more memory than you need which is wasteful in the case of longer strings and/or strict filters. You could instead allocate the string on demand inside the if clause.
These are common options:
Receive the allowed size as parameter by pointer, overwrite it with the actual size, return the array as return value.
Receive the output array as parameter by pointer, update as required, return the actual size as return value.
Append a sentinel value to the output array (here a null pointer), as suggested in the other answer.
Use a more sophisticated data structure as a return value. You could use a struct, which stores the size alongside the array or a linked list.
Example (untested):
typedef char* mystring;
typedef mystring* mystringarray;
typedef struct { mystringarray *arr; size_t size } mysizedstringarray;
/* returns filtered array, size will be updated to reflect the valid size */
mystringarray* myfun1(mystringarray in, size_t* size);
/* out will be allocated and populated, actual size is returned */
size_t myfun2(mystringarray in, size_t size, mystringarray* out);
/* output array contains valid items until sentinel value (NULL) is reached */
mystringarray* myfun3(mystringarray in, size_t size);
/* returns filtered array with actual size */
mysizedstringarray myfun4(mystringarray in, size_t size);
I needed a character array containing a dynamic number of character arrays based on the number of files in a specific folder. I was able to accomplish this by initializing char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH] and then using FullPathNames = malloc( sizeof(*FullPathNames) * NumOfFiles * MAX_FILENAME_AND_PATHNAME_LENGTH ) ) after I know how many files another function discovered( which I have not provided). This process works flawlessly.
I can only use ANSI C; I am specifically using LabWindows CVI 8.1, to compile my code. I cannot use any other compiler. The below code is doing what I want. I can fill this array easily enough with the following code:
Strcpy(FullPathNames[0],”Test Word”);
char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH];
size_t Size;
NumOfFiles = NumberOfUserFiles(“*.txt”, “C:\\ProgramData” );
FullPathNames = malloc( sizeof(*FullPathNames) * NumOfFiles * MAX_FILENAME_AND_PATHNAME_LENGTH ) );
Size = sizeof(*FullPathNames) * NumOfFiles;
Memset(FullPathNames,0,Size);
However, I would like to be able to pass FullPathNames which is an array of pointers to a variable amount of character arrays into a method. I want this method to be able to remove a single character array at a given index.
I am calling the method with the following code.
Remove_Element(FullPathNames,1, NumOfFiles);
The code for Remove_Element:
void Remove_Element( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], int Index, int Array_Length )
{
int i;
char String[MAX_FILENAME_AND_PATHNAME_LEN];
char (*NewArray)[MAX_FILENAME_AND_PATHNAME_LEN];
int NewLength = Array_Length - 1;
size_t Size;
NewArray = malloc( sizeof( *NewArray) * NewLength * ( MAX_FILENAME_AND_PATHNAME_LEN ) );
Size = sizeof( *NewArray ) * NewLength;
memset(NewArray, 0, Size);
for ( i = Index; i < Array_Length - 1; i++ )
{
memcpy(String,Array[i+1],MAX_FILENAME_AND_PATHNAME_LEN); // Remove last index to avoid duplication
strcpy( Array[Index], String );
}
Array = NewArray;
}
My expectation of what I have currently is that the original data of FullPathNames remains except for the index that I removed, by copying data from index + 1, and the original pointers contained within FullPathNames is of course updated. Since I also wanted to shrink the array I attempted to set the array equal to the new array. The following information explains my attempts at debugging this behavior.
The watch variables present the following information as I enter the method.
FullPathNames = XXXXXX
NewArray = Unallocated
Array = XXXXXX
After I fill the new temporary Array the following happens:
FullPathNames = XXXXXX
NewArray = YYYYY
Array = XXXXXX
As I exit the method the following happens:
FullPathNames = XXXXXX
NewArray = YYYYY
Array = YYYYY
I was attempting to modify FullPathNames by passing it in as a pointer. I originally tried this task by using realloc but that just resulted in a free pointer exception.
Notes:
MAX_FILENAME_AND_PATHNAME_LENGTH = 516;
If I understand correctly, what you want to do is to modify the FullPathNames Pointer in the code part where you initialize your original array.
With your declartion of FullPatchNames
char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH]
you basically declare a pointer to an array of MAX_FILENAME_AND_PATHNAME_LENGTH char elements. With your call to void Remove_Element(...) you just give a copy of this pointer to the local variable Array valid inside your function. Because of this Array = NewArray;, only changes the local copy of your pointer inside the function, not FullPathNames.
If you want to change the value of FullPathNames you must give a pointer to this pointer to your function. The Prototype of Remove_Element must look like this:
void Remove_Element( char (**Array)[MAX_FILENAME_AND_PATHNAME_LEN],
int Index, int Array_Length )
Now Array is a Pointer to an Pointer to an (one dimansional) array of char. By dereferencing this Pointer, you can change your original Pointer FullPathNames to point to your new object you created inside your function. You must modify the call to this function to Remove_Element(&FullPathNames,1, NumOfFiles);. To read from Array, you must dereference it using the * operator:
memcpy(String,*Array[i+1],MAX_FILENAME_AND_PATHNAME_LEN);
...
Array = NewArray;
Warning: This code will now produce a memory leak, since you are loosing your reference to your orignal object. You should remove this using the free() function somewhere in your code!
There seems to exist a certain lack of knowledge about the syntax in C language first and foremost.
char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH]
This is one example. The syntax shown here would be read by a c- programmer as:
Semicolon is missing - maybe #define voodoo somewhere!
char (*FullPathNames)... - a function pointer! oh wait why square brackets next?!
Maybe he wanted to say char *FullPathNames; or he wanted char FullPathNames[MAX_FILENAME_AND_PATH_NAME_LENGTH]; Hm...
So here the first 101:
char foo[50]; // A fixed size array with capacity 50 (49 chars + '\0' max).
char *foo = NULL; // a uninitialized pointer to some char.
char (*foo)(); // a pointer to a function of signature: char(void).
char *foobar[50]; // This is an array of 50 pointers to char.
Depending on where your char foo[50]; is located (in the code file, in a function, in a structure definition), the storage used for it varies.
char foo1[50]; // zerovars section.
char foo2[50] = { 0 }; // initvars section
char foo3[50] = "Hello World!"; // also initvars section
void FooTheFoo( const char *foo )
{
if(NULL != foo )
{
printf("foo = %s\n", foo);
}
}
int main(int argc, const char *argv[])
{
char bar[50] = "Message from the past."; // bar is located on the stack (automatic variable).
FooTheFoo(bar); // fixed size array or dynamic array - passed as a (const pointer) in C.
return 0;
}
Now we got the basics down, lets look at 2-dimensional dynamic array.
char **matrix = NULL;
A pointer to a pointer of char. Or a pointer to an array of pointers to chars or an array of pointers to pointers to arrays of chars.
As lined out, there is no "meta" information regarding to what a char* or a char ** point to beyond that finally the dereferenced item will be of type char. And that it is a pointer to a pointer.
If you want to make a 2-dimensional array out of it, you have to initialize accordingly:
const size_t ROW_COUNT = 5;
const size_T COL_COUNT = 10;
char **myMatrix = malloc(sizeof(char *) * ROW_COUNT);
// check if malloc returned NULL of course!
if( NULL != myMatrix )
{
for(size_t row = 0; row < ROW_COUNT; row++ )
{
myMatrix[row] = malloc(sizeof(char) * COL_COUNT);
if( NULL == myMatrix[row] ) PanicAndCryOutLoudInDespair();
for(size_t col = 0; col < COL_COUNT; col++ )
{
myMatrix[row][col] = 0;
}
// of course you could also write instead of inner for - loop:
// memset(myMatrix[row], 0, sizeof(char) * COL_COUNT);
}
}
Last not least, how to pass such a 2-dimensional array to a function? As the char** construct does not contain the meta information regarding sizes, in the general (inner not a 0 terminated string) case, you would do it like that:
void FooIt( const char **matrix, size_t rowCount, size_t colCount )
{ // Note: standard checks omitted! (NULL != matrix, ...)
putchar(matrix[0][0]);
}
Last, if you want to get rid of your 2D dynamic array again, you need to properly free it.
void Cleanup2DArray( char **matrix, size_t rowCount )
{
for(size_t row = 0; row < rowCount; row++ )
{
free(matrix[row];
}
free(matrix);
}
The only thing more to say about it I leave to other gentle contributors. One thing coming to mind is how to express const-ness correctly for those multi-dimensional things.
const char **
const char const * const *
etc.
With this, you should be able to spot the places where you went wrong in your code and fix it.
The pointer you're passing is just a value. That it holds an address means you can dereference it to modify what it points to, but it doesn't mean changing its value directly (your assignment statement) will affect the caller-parameter. Like everything else in C, if you want to modify something by-address, then an address is exactly what you need to do it. If the thing you're modifying is a pointer, then the address of the pointer (through a pointer-to-pointer parameter) is the generally prescribed solution.
However, I can tell you the syntax and housekeeping to do that is... uninviting in your case. A simple pointer is easy enough, but a pointer-to-array-of-N isn't so simply. Were I you his would simply use the return result of the function itself, which is otherwise currently being unused and void. Declare your function like this:
char (*Remove_Element( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN],
int Index, int Array_Length ))[MAX_FILENAME_AND_PATHNAME_LEN]
{
....
return Array; // or whatever else you want to return so
// long as the type is correct.
}
and simply have the caller do this:
Array = RemoveElement(Array, Index, Array_Length);
A working variation of my solution appears below. The reason I had to do it this way is because while I was able to dereference (**Array)[MAX_FILENAME_AND_PATHNAME_LEN] I was only able to modify the first string array in the array.
The string array was initialized and filled several strings. While I could reference a string contained within *Array[0] but was unable to reference any of the other strings. The resulting array will replace the original array. This method will only work in the initial code block where the array to be replaced is initialized.
#define MAX_FILENAME_AND_PATHNAME_LEN MAX_FILENAME_LEN + MAX_PATHNAME_LEN
/*
This method was designed to free the memory allocated to an array.
*/
void FreeFileAndPathArrays( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN] )
{
free( Array );
}
/*
This method was designed to remove an index from an array. The result of this method will shrink the array by one.
*/
void Remove_Element( char (**ArrayPointer)[MAX_FILENAME_AND_PATHNAME_LEN],int Index, int *Array_Length, char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN] )
{
int i = 0;
int j = 0;
char String[MAX_FILENAME_AND_PATHNAME_LEN];
char (*NewArray)[MAX_FILENAME_AND_PATHNAME_LEN];
char (*GC)[MAX_FILENAME_AND_PATHNAME_LEN];
int Length = *Array_Length;
int NewLength = Length - 1;
size_t Size;
NewArray = malloc( sizeof( *NewArray) * NewLength * ( MAX_FILENAME_AND_PATHNAME_LEN ) );
Size = sizeof( *NewArray ) * NewLength;
memset(NewArray, 0, Size);
UI_Display("Test Block:");
for ( j = 0; j < NewLength; j++ )
{
if ( j != Index )
{
memcpy(String,Array[j],MAX_FILENAME_AND_PATHNAME_LEN);
strcpy( Array[Index], String );
Fill(NewArray,String,j);
UI_Display(String);
}
}
GC = Array;
*ArrayPointer = NewArray;
free(GC);
*Array_Length = *Array_Length - 1;
}
/*
This method was designed to place a string into an index.
*/
void Fill( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], const char * String, int Index)
{
strcpy( Array[Index], String );
}
/*
This method was designed to place fill each string array contained within the array of string arrays with 0's.
*/
void PrepareFileAndPathArrays( char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LEN], int ROWS )
{
size_t Size;
Size = sizeof( *FullPathNames ) * ROWS;
memset(FullPathNames, 0, Size);
}
I have an array of names stored in char *namelist[]. When I pass it to a function, I'm unable to display all of the names in the namelist:
int ReadListOfName(const char* names[])
{
//Note: I always get the len = 1
// Anyway I can get total items in names
int len = sizeof(names)/sizeof(char*);
for (i=0; i<len; i++)
printf("%d-%s\n",i,names[i]);
return 0;
}
int main(void)
{
const char* names[] = {"a","b","c"};
ReadListOfName(names);
return 0;
}
What's the problem?
int len = sizeof(names)/sizeof(char*);
This doesn't get you the number of elements, sizeof doesn't do what you want on pointers. You have to pass the length as an additional argument to the function. Also discussed in this C FAQ. You could try:
int ReadListOfName(const char* names[], size_t len)
/* ... */
ReadListOfName(names, sizeof(names)/sizeof(names[0]));
int ReadListOfName(const char* names[])
In this names essentially becomes char ** rather than char * [] as defined your main.
You'll need to pass in another argument to ReadListOfName specifying the length of the array or have a terminating value in your array like argv does. When passed to a function, an array will decay to a pointer; a char*[] will decay to a char**, as you're passing the address of the first element in the array. Therefore your function is in fact interpreted as:
int ReadListOfName(const char **names)
And you're actually equating sizeof(char**)/sizeof(char*), which won't give you the number of elements in the array (it'll probably give you 1).
Add a length argument and then just calculate len before passing it ReadListOfName.
Note that rather than dividing sizeof(names) by sizeof(char*) to get the number of elements in the array, you can instead divide by sizeof(*names), and you wouldn't need to worry about changing char* if you change the type of the elements in names:
int len = sizeof(names)/sizeof(*names);
As the other answers already explain what happens to the array reference when passing it to the function, please find an approach to solve the issue without adding another parameter to the method printing the names.
You might like to add a stopper element to your list like so:
#include <stdio.h>
int ReadListOfName(const char ** names)
{
for (int i=0; names[i]; i++)
printf("%d-%s\n",i,names[i]);
return 0;
}
int main(void)
{
const char* names[] = {"a","b","c", NULL}; /* Please note the additional, last element. */
ReadListOfName(names);
return 0;
}
The essential difference of this approach to the one passing two arguments discribing the list names[], is the fact that its use is less error-prone as the information of the list's size is drawn from the list itself, but from a second independently provided value.
you should pass an additional argument which will explicitly mention the length of the array. and where you are initializing setup some MACRO to fiddle with sizeofs.
sizeof(AnyPointer) gives word size. In case of 32-bit OS, 4 will be returned. similarly 8 will be returned in 64-bit machine.
So sizeof(char*) == sizeof(float*) == sizeof(int*) is true.
If your OS is 32-bit,
sizeof(names) will be 4.
sizeof(char*) also 4.
Obviously you will get len = 1.
I want to make a FUNCTION which calculates size of passed array.
I will pass an Array as input and it should return its length. I want a Function
int ArraySize(int * Array /* Or int Array[] */)
{
/* Calculate Length of Array and Return it */
}
void main()
{
int MyArray[8]={1,2,3,0,5};
int length;
length=ArraySize(MyArray);
printf("Size of Array: %d",length);
}
Length should be 5 as it contains 5 elements though it's size is 8
(Even 8 will do but 5 would be excellent)
I tried this:
int ArraySize(int * Array)
{
return (sizeof(Array)/sizeof(int));
}
This won't work as "sizeof(Array)" will retun size of Int Pointer.
This "sizeof" thing works only if you are in same function.
Actually I am back to C after lots of days from C# So I can't remember (and Missing Array.Length())
Regards!
You cannot calculate the size of an array when all you've got is a pointer.
The only way to make this "function-like" is to define a macro:
#define ARRAY_SIZE( array ) ( sizeof( array ) / sizeof( array[0] ) )
This comes with all the usual caveats of macros, of course.
Edit: (The comments below really belong into the answer...)
You cannot determine the number of elements initialized within an array, unless you initialize all elements to an "invalid" value first and doing the counting of "valid" values manually. If your array has been defined as having 8 elements, for the compiler it has 8 elements, no matter whether you initialized only 5 of them.
You cannot determine the size of an array within a function to which that array has been passed as parameter. Not directly, not through a macro, not in any way. You can only determine the size of an array in the scope it has been declared in.
The impossibility of determining the size of the array in a called function can be understood once you realize that sizeof() is a compile-time operator. It might look like a run-time function call, but it isn't: The compiler determines the size of the operands, and inserts them as constants.
In the scope the array is declared, the compiler has the information that it is actually an array, and how many elements it has.
In a function to which the array is passed, all the compiler sees is a pointer. (Consider that the function might be called with many different arrays, and remember that sizeof() is a compile-time operator.
You can switch to C++ and use <vector>. You can define a struct vector plus functions handling that, but it's not really comfortable:
#include <stdlib.h>
typedef struct
{
int * _data;
size_t _size;
} int_vector;
int_vector * create_int_vector( size_t size )
{
int_vector * _vec = malloc( sizeof( int_vector ) );
if ( _vec != NULL )
{
_vec._size = size;
_vec._data = (int *)malloc( size * sizeof( int ) );
}
return _vec;
}
void destroy_int_vector( int_vector * _vec )
{
free( _vec->_data );
free( _vec );
}
int main()
{
int_vector * myVector = create_int_vector( 8 );
if ( myVector != NULL && myVector->_data != NULL )
{
myVector->_data[0] = ...;
destroy_int_vector( myVector );
}
else if ( myVector != NULL )
{
free( myVector );
}
return 0;
}
Bottom line: C arrays are limited. You cannot calculate their length in a sub-function, period. You have to code your way around that limitation, or use a different language (like C++).
You can't do this once the array has decayed to a pointer - you'll always get the pointer size.
What you need to do is either:
use a sentinel value if possible, like NULL for pointers or -1 for positive numbers.
calculate it when it's still an array, and pass that size to any functions.
same as above but using funky macro magic, something like: #define arrSz(a) (sizeof(a)/sizeof(*a)).
create your own abstract data type which maintains the length as an item in a structure, so that you have a way of getting your Array.length().
What you ask for simply can't be done.
At run time, the only information made available to the program about an array is the address of its first element. Even the size of the elements is only inferred from the type context in which the array is used.
In C you can't because array decays into a pointer(to the first element) when passed to a function.
However in C++ you can use Template Argument Deduction to achieve the same.
You need to either pass the length as an additional parameter (like strncpy does) or zero-terminate the array (like strcpy does).
Small variations of these techniques exist, like bundling the length with the pointer in its own class, or using a different marker for the length of the array, but these are basically your only choices.
int getArraySize(void *x)
{
char *p = (char *)x;
char i = 0;
char dynamic_char = 0xfd;
char static_char = 0xcc;
while(1)
{
if(p[i]==dynamic_char || p[i]==static_char)
break;
i++;
}
return i;
}
int _tmain(int argc, _TCHAR* argv[])
{
void *ptr = NULL;
int array[]={1,2,3,4,5,6,7,8,9,0};
char *str;
int totalBytes;
ptr = (char *)malloc(sizeof(int)*3);
str = (char *)malloc(10);
totalBytes = getArraySize(ptr);
printf("ptr = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(int)));
totalBytes = getArraySize(array);
printf("array = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(int)));
totalBytes = getArraySize(str);
printf("str = total bytes = %d and allocated count = %d\n",totalBytes,(totalBytes/sizeof(char)));
return 0;
}
Not possible. You need to pass the size of the array from the function, you're calling this function from. When you pass the array to the function, only the starting address is passed not the whole size and when you calculate the size of the array, Compiler doesn't know How much size/memory, this pointer has been allocated by the compiler. So, final call is, you need to pass the array size while you're calling that function.
Is is very late. But I found a workaround for this problem. I know it is not the proper solution but can work if you don't want to traverse a whole array of integers.
checking '\0' will not work here
First, put any character in array at the time of initialization
for(i=0;i<1000;i++)
array[i]='x';
then after passing values check for 'x'
i=0;
while(array[i]!='x')
{
i++;
return i;
}
let me know if it is of any use.
Size of an arry in C is :
int a[]={10,2,22,31,1,2,44,21,5,8};
printf("Size : %d",sizeof(a)/sizeof(int));