Find size of array without using sizeof - c

I was searching for a way to find the size of an array in C without using sizeof and I found the following code:
int main ()
{
int arr[100];
printf ("%d\n", (&arr)[1] - arr);
return 0;
}
Can anyone please explain to me how is it working?

&arr is a pointer to an array of 100 ints.
The [1] means "add the size of the thing that is pointed to", which is an array of 100 ints.
So the difference between (&arr)[1] and arr is 100 ints.
(Note that this trick will only work in places where sizeof would have worked anyway.)

&arr gives you a pointer to the array. (&arr)[1] is equivalent to *(&arr + 1). &arr + 1 gives you a pointer to the array of 100 ints that follows arr. Dereferencing it with * gives you that array that follows. Since this array is used in an additive expression (-), it decays to the pointer to its first element. The same happens to arr in the expression. So you subtract to pointers, one pointing to the non-existent element right after arr and the other pointing to the first element of arr. This gives you 100.
But it's not working. %d is used for int. Pointer difference returns you ptrdiff_t and not int. You need to use %td for ptrdiff_t. If you lie to printf() about the types of the parameters you're passing to it, you get well-deserved undefined behavior.
EDIT: (&arr)[1] may cause undefined behavior. It's not entirely clear. See the comments below, if interested.

Generally (as per visual studio),
for an array &arr is same as arr ,which return the starting base address of our function.
(&arr)[0] is nothing but &arr or arr
ex: it will return some address : 1638116
Now, (&arr)[1] means we are started accessing the array out of bounce means next array or next segment of the size of present array(100 ahead).
ex: it will return some address : 1638216
Now, subtracting (&arr)[1] - (&arr)[0]=100

&variable gives location of the variable (call it as P)
&variable + 1 gives address of the location next to the variable. (call it as N)
(char*)N-(char*)P gives how many characters are there between N and P. Since each character is 1 byte sized, so the above result gives the number of bytes P and N. (which equals to the size of array in bytes).
Similarly,
(char*) (a+1)-(char*)a; gives size of each element of the array in bytes.
So the number of elements in the array = (size of array in bytes)/(size of each element in the array in bytes)
#include<stdio.h>
int main()
{
int a[100];
int b = ((char*)(&a+1)-(char*)(&a));
int c = (char*) (a+1)-(char*)a;
b = b/c;
printf("The size of array should be %d",b);
return 0;
}

int arry[6]={1,2,3,4,5,6} //lets array elements be 6,
so...
size in byte = (char*)(arry+6)-(char *)(arry)=24;

int main ()
{
int arr[100];
printf ("%d\n", ((char*)(&arr+1) - (char*)(&arr))/((char*) (arr+1) -(char*) (arr)));
return 0;
}

Related

array passed as array and pointer-C

Why does this program produce p and q as outputs? What is the difference between passing an array as a pointer or as an array.
#include<stdio.h>
void fun(char i[]){
printf("%c,%c", i[1],i[2]);
}
void fun2(char *i){
printf("\n%c,%c", i,i+1);
}
int main(){
char ar[] = {"Aba"};
fun(ar);
fun2(ar);
return 0;
}
Output:
b,a
p,q
You are printing the ASCII conversion of a pointer address in the second function. You must dereference the pointer via *i and *(i+1).
To print the value you should use either *i and *(i+1) or i[0] and i[1] in both the functions. i contains the first address cell of the array you have passed. In either cases, both pass their address.
what is the difference between passing array as pointer or as an
array.
Both functions, fun and fun2, signatures are equivalent. So, you don't really have an array in fun() as you think.
This is because in C, when you pass an array to a function, it gets converted into a pointer to its first element.
So, this statement in fun2()
printf("\n%c,%c", i,i+1);
doesn't print the chars but the addresses i and i+1. And that's not right either since they don't match with the format specifies you have.
When I compiled your code with gcc, it warns:
In function ‘fun2’:
warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘char *’ [-Wformat=]
printf("\n%c,%c", i,i+1);
^
warning: format ‘%c’ expects argument of type ‘int’, but argument 3 has type ‘char *’ [-Wformat=]
As you can see, the format specifiers and the arguments you pass don't match. To print values that i and i+1
point to, you can print it just like how you do in fun():
int fun2(char *i){
printf("\n%c,%c", i[1],i[2]);
}
Hope my long answer here helps!
I have taken integers, the concept remains the same with any data type: char, floats, etc, etc.
Okay, a quick short lesson on arrays and pointers.
Thumb rule 1: Arrays and pointers are almost always interchangable but there are exceptions!
Taking a 1-D array, we can declare it like this :-
int arr[10];
This declares a variable named arr which can hold 10 integer elements.
I can similarly use the pointer notation to represent this array using a pointer variable or by using the array name (arr) itself.
printf ("%d", arr[2]); // Array method : will print out the third element, indexing starts from 0
Thumb rule 2: Array name(be it 1D 2D 3D 4D) always decays into a pointer or an address.
printf ("%lu", arr) //will print out the base address of the array, i.e address of the first element
How to print the value using a pointer ? Simply, dereference it using * operator.
printf("%d", *arr) //Pointer notation - will print the first value
How to reference the array using another variable?
int *ptr = arr; //Pointer notation - just simply write the array name as it decays into an address
printf("%d", *ptr); //Pointer notation - prints the first element
Many people say int *ptr is pointer to an array.
In reality it's not. It's actually a pointer to an integer not an array. Why?
Because in the first place we are storing the address of the first integer of the array and then we can traverse it by incrementing the pointer. So, in real pointer is storing the address of an integer(First integer).
Now, coming to 2D arrays :-
Declaration:-
int arr[2][3]; // arrays of 2 rows and 3 columns, total 6 elements
Same above rules implies :-
printf("%d", arr[0][1]); //prints the second element of the first row.
printf("%lu", arr) //prints the base address of the 2D array
Coming to Pointer Notation :-
printf("%d", *(*(arr + 0) + 1); // how this works?
arr contains the address. Adding a integer to it with make you jump to that row.
arr + 1 // gives the second row, i.e. arr is currently pointing to the first element of second row.
Now, further adding an integer to it, will make you skip to that specified column in that particular row.
((arr + 1) // second row + 2 ) // will you skip to third element of the second row
This is the implicit pointer notation that language gives you, when you choose to treat the array name as a pointer.
Now coming to your problem : - Explicit Pointer Notation:-
What are you trying to achieve is, storing the base address of the 2D array in a pointer.
How to correctly do that ?
int (*ptr)[3]; //reading it goes like this - ptr is a pointer to a 1D array of 3 ints
The 3 here specifies the number of columns your 2D array has.
So what it is doing is, trying to store the base address of first 1D array of that 2D array (which means 0th row base address) into the pointer.
The rest remains the same.
int (*ptr)[3] = arr; // storing the 2D array in ptr
Now, you can use it as a normal pointer(Pointer notation applies on it)
(ptr + 1) //now ptr is pointer to the Second 1D array of that 2D array or you can say to the second row's first element.
Another way you can catch an array in a function is like this:-
I use it very less though.
int main()
{
int arr[2][2];
fun(arr);
}
void fun(int catch[][])
{
}
// This is simple to understand and as well as to relate. Now, again catch can be used as pointer or as an array. It depends on you :)
void fun1(int (*ptr)[2])
{
//my way
printf("%d", ptr[1][1]);
printf("%d", *(*(ptr + 1) + 1));
//answer will be the same
}
//Ptr now contains that 2D array base address, again can be used as an array or a pointer :)

Why is the declaration *(*(arr+1)+2) not working when I am passing the a 2d array to a function (tes).t

#include<stdio.h>
int test(int *x);
void main(){
int arr[2][3], a;
arr[1][2] = 2;
printf("%d\n", test((int *)arr));
printf("%d\n", *(*(arr+1)+2));
}
int test(int *prr){
int a;
a = *(*(prr+1)+2);
return a;
}
The above code is giving me the following error:
error: invalid type argument of unary ‘*’ (have ‘int’)
a = *( *(prr+1)+2);
^
but the same declaration works in the main function:
printf("%d\n", *( *(arr+1)+2)).
Also when I replace it with *((arr+1*3) + 2), 3 being the size of 2nd dimension, in the function test, it worked and I could not understand how ??? I really want to know the reason. please help!!!
And why is their a need to type cast a 2D array, but not 1D array when passing to a function.
I used the help of http://www.geeksforgeeks.org/pass-2d-array-parameter-c/, but the reason was not there.
In main function arr is an array of arrays of int. *(*(arr+1)+2) is equivalent to *(arr[1] + 2) = arr[1][2]. arr[1] is an array and will decay to pointer to first element arr[1][0].
In test, prr is a pointer to int. *(prr+1)+2 is equivalent to *(prr[1] + 2). prr[1] is an int. This makes the expression prr[1] + 2 an int. Operand of unary * operator must be a pointer variable.
Change function prototype to
int test(int x[][3]);
and make function call as
printf("%d\n", test(arr));
in function test(int *prr) prr points to a integer not a array.
so *(Prr+1) is a integer, but '*' unary operator is only applied to pointers.
Okay, a quick short lesson on arrays and pointers.
Thumb rule 1: Arrays and pointers are almost always interchangable but there are exceptions!
Taking a 1-D array, we can declare it like this :-
int arr[10];
This declares a variable named arr which can hold 10 integer elements.
I can similarly use the pointer notation to represent this array using a pointer variable or by using the array name (arr) itself.
printf ("%d", arr[2]); // Array method : will print out the third element, indexing starts from 0
Thumb rule 2: Array name(be it 1D 2D 3D 4D) always decays into a pointer or an address.
printf ("%lu", arr) //will print out the base address of the array, i.e address of the first element
How to print the value using a pointer ? Simply, dereference it using * operator.
printf("%d", *arr) //Pointer notation - will print the first value
How to reference the array using another variable?
int *ptr = arr; //Pointer notation - just simply write the array name as it decays into an address
printf("%d", *ptr); //Pointer notation - prints the first element
Many people say int *ptr is pointer to an array.
In reality it's not. It's actually a pointer to an integer not an array. Why?
Because in the first place we are storing the address of the first integer of the array and then we can traverse it by incrementing the pointer. So, in real pointer is storing the address of an integer(First integer).
Now, coming to 2D arrays :-
Declaration:-
int arr[2][3]; // arrays of 2 rows and 3 columns, total 6 elements
Same above rules implies :-
printf("%d", arr[0][1]); //prints the second element of the first row.
printf("%lu", arr) //prints the base address of the 2D array
Coming to Pointer Notation :-
printf("%d", *(*(arr + 0) + 1); // how this works?
arr contains the address. Adding a integer to it with make you jump to that row.
arr + 1 // gives the second row, i.e. arr is currently pointing to the first element of second row.
Now, further adding an integer to it, will make you skip to that specified column in that particular row.
((arr + 1) // second row + 2 ) // will you skip to third element of the second row
This is the implicit pointer notation that language gives you, when you choose to treat the array name as a pointer.
Now coming to your problem : - Explicit Pointer Notation:-
What are you trying to achieve is, storing the base address of the 2D array in a pointer.
How to correctly do that ?
int (*ptr)[3]; //reading it goes like this - ptr is a pointer to a 1D array of 3 ints
The 3 here specifies the number of columns your 2D array has.
So what it is doing is, trying to store the base address of first 1D array of that 2D array (which means 0th row base address) into the pointer.
The rest remains the same.
int (*ptr)[3] = arr; // storing the 2D array in ptr
Now, you can use it as a normal pointer(Pointer notation applies on it)
(ptr + 1) //now ptr is pointer to the Second 1D array of that 2D array or you can say to the second row's first element.
Another way you can catch an array in a function is like this:-
I use it very less though.
int main()
{
int arr[2][2];
fun(arr);
}
void fun(int catch[][])
{
}
// This is simple to understand and as well as to relate. Now, again catch can be used as pointer or as an array. It depends on you :)
void fun1(int (*ptr)[2])
{
//my way
printf("%d", ptr[1][1]);
printf("%d", *(*(ptr + 1) + 1));
//answer will be the same
}
//Ptr now contains that 2D array base address, again can be used as an array or a pointer :)
In you function main arr is a 2-d array of int and thus, this works -
printf("%d\n", *(*(arr+1)+2)); // you dereference it twice to get value
But in your function test, parameter is of type int * and therefore , this expression -
a = *( *(prr+1)+2); // prr is of type int *
gives error as you try to dereference int * twice. There is only one level of indirection , so you need to dereference once. Also, you could achieve same by passing 2-d array directly without cast and it would work.
Something like this -
int test(int **prr){
// you code
}
and in main you can call it like this -
int x = test(arr);

Why the output is same in all three cases?

Can somebody please explain why the output is same in all three snippets below.
and what exactly does the 0th element of array represents.
int main(void) {
char arr[10];
scanf("%s",&arr[0]);
printf("%s",arr);
return 0;
}
int main(void) {
char arr[10];
scanf("%s",&arr[0]);
printf("%s",&arr);
return 0;
}
int main(void) {
char arr[10];
scanf("%s",&arr[0]);
printf("%s",*&arr);
return 0;
}
& ("address of") and * ("dereference pointer") cancel each other out, so *&foo is the same as foo.
Your second snippet is wrong. It passes &arr (a pointer to an array of 10 chars, char (*)[10]) to printf %s, which expects a pointer to char (char *). It just so happens that on your platform those two types have the same size, use the same representation, and are passed the same way to printf. That's why the output looks correct.
As for the difference: arr is a an array of chars. Evaluating an array (i.e. using it anywhere other than the operand of & or sizeof) yields a pointer to its first element.
&arr yields a pointer to the whole array. An array has no runtime structure (that is, at runtime an array is its elements), so the address of the array is also the address of its first element. It's just that the first element is smaller than the whole array and the two addresses have different types.
arr[0] represents the first element of array arr. &arr[0] is the address of first element of array. In all of the three snippet, scanf is reading a string from standard input and will store in array arr.
In first snippet
printf("%s",arr);
will print the stored string in array arr. %s expects an argument of char * type and &arr[0] is of that type and so is arr after it will decay to pointer to its first element.
In second snippet, &arr is the address of array arr and is of type char (*)[10]. Using wrong specifier will invoke undefined behavior.
In third snippet, applying * on &arr will dereference back it to address of the first element of array arr which is of type char * as said above.
Snippet first and third are correct and will give same output for the same input under the condition that input string should not be greater than 10 characters including '\0'. Third code will invoke undefined behavior and nothing can be said in this case.

How pointer to array works?

int s[4][2] = {
{1234, 56},
{1212, 33},
{1434, 80},
{1312, 78}
};
int (*p)[1];
p = s[0];
printf("%d\n", *(*(p + 0))); // 1234
printf("%d\n", *(s[0] + 0)); // 1234
printf("%u\n", p); // 1256433(address of s[0][0])
printf("%u\n", *p); // 1256433(address of s[0][0])
Can anyone explain why doing *(*(p + 0)) prints 1234, and doing *(s[0] + 0) also prints 1234, when p = s[0] and also why does p and *p gives the same result?
Thanking you in anticipation.
This is the way arrays work in C -- arrays are not first class types, in that you can't do anything with them other than declaring them and getting their size. In any other context, when you use an expression with type array (of anything) it is silently converted into a pointer to the array's first element. This is often referred to as an array "decaying" into a pointer.
So lets look at your statements one by one:
p = s[0];
Here, s has array type (it's an int[4][2] -- a 2D int array), so its silently converted into a pointer to its first element (an int (*)[2], pointing at the word containing 1234). You then index this with [0] which adds 0 * sizeof(int [2]) bytes to the pointer, and then dereferences it, giving you an int [2] (1D array of 2 ints). Since this is an array, its silently converted into a pointer to its first element (an int * pointing at 1234). Note that this is the same pointer as before the index, just the pointed at type is different.
You then assign this int * to p, which was declared as int (*)[1]. Since C allows assigning any pointer to any other pointer (even if the pointed at types are different), this works, but any reasonable compiler will give you a type mismatch warning.
p now points at the word containing 1234 (the same place the pointer you get from s points at)
printf("%d\n", *(*(p+0)));
This first adds 0*sizeof(int[1]) to p and dereferences it, giving an array (int[1]) that immediately decays to a pointer to its first element (an int * still pointing at the same place). THAT pointer is then dereferenced, giving the int value 1234 which is printed.
printf("%d\n", *(s[0]+0));
We have s[0] again which via the multiple decay and dereference process noted in the description of the first line, becomes an int * pointing at 1234. We add 0*sizeof(int) to it, and then dereference, giving the integer 1234.
printf("%u\n", p);
p is a pointer, so the address of the pointer is simply printed.
printf("%u\n",*p)
p is dereferenced, giving an int [1] (1D integer array) which decays into a pointer to its first element. That pointer is then printed.
s[0]points to a location in memory. That memory location happens to be the starting point of int s[4][2]. When you make the assignment p = s[0], p and p+0 also point to s[0]. So when you print any one of these with a "%d" specifier, you will get the value stored at that location which happens to be `1234'. If you would like to verify the address is the same for all of these, use a format specifier "%p" instead of "%d".
EDIT to address OP comment question...
Here is an example using your own int **s:
First, C uses pointers. Only pointers. No arrays. The [] notation gives the appearance of arrays, but any variable that is created using the [] notation (eg. int s[4][2]) is resolved into a simple pointer (eg. int **s). Also, a pointer to a pointer is still just a pointer.
int a[8]={0}; (or int *a then malloced)
will look the same in memory as will:
int a[2][4]; ( or in **a=0; then malloced)
The statment:
s[row][col] = 1;
creates the same object code as
*(*(s + row) + col) = 1;
It is also true that
s[row] == *(s + row)
Since s[row] resolves to a pointer, then so does *(s + row)
It follows that s[0] == *(s + 0) == *s
If these three are equal, whatever value is held at this address will be displayed when printing it.
It follows that in your code: given that you have assigned p = s[0]; and s[0] == *s
*(*(p + 0)) == *(s[0] + 0) == *s[0] == **s
printf("%d\n", >>>fill in any one<<<); //will result in 1234
Note, in the following printf statements, your comment indicates addresses were printed. But because you used the unsigned int format specifier "%u",
Consider p == s[0]; which is a pointer to the first location of s. Note that either s[0][0] or **s would give you the value held at the first location of s, but s[0] is the _address_ of the first memory location of s. Therefore, since p is a pointer, pointing to the address at s[0], the following will give you the address of p, or s[0] (both same):
printf("%p\n", *p); // 1256433(address of s[0][0])
As for *p, p was created as int (*p)[1]; and pointer array of 1 element. an array is resolved into a pointer, so again, in the following you will get the address pointing to s[0]:
printf("%u\n", **p);
In summary, both p and *p are pointers. Both will result in giving address when printed.
Edit 2 Answer to your question: So my question is what is the difference between a simple pointer and a pointer to an array?
Look toward the bottom of this tutorial download a pdf. It may explain it better...
But in short, C Does not implement arrays in the same way other languages do. In C, an array of any data type always resolves into a pointer. int a[10]; is just really int *a;, with memory set aside for space to hold 10 integers consecutively. In memory it would look like:
a[0] a[9]
|0|0|0|0|0|0|0|0|0|0| (if all were initialized to zero)
Likewise you would be tempted to think of float b[2][2][2]; as a 3 dimensional array: 2x2x2, it is not. It is really a place in memory, starting at b[0] that has room for 8 floating point numbers. Look at the illustrations HERE.

Size of char pointer array from function

Using this code:
#include <stdio.h>
void printSize(char *messages[]) {
printf("%d", sizeof(messages) / sizeof(char *));
}
int main(void) {
printf("Size when through passing direct to function: ");
printSize((char *[]){"Zero", "One", "Two", "Three"});
printf("\n");
printf("Size when calculating in main: %d\n", sizeof((char *[]){"Zero", "One", "Two", "Three"}) / sizeof(char *));
return 1;
}
I get output:
Size when through passing direct to function: 1
Size when calculating in main: 4
I understand there is no way to get the correct amount of elements in a char* array, but I am curious as to why they are giving different results.
It's because char *messages[] is just syntactic sugar for char **messages, so you're just getting the size of a pointer, not the size of your whole array.
You can't, without passing the size along as another parameter.
You should check out the comp.lang.c FAQ section on Arrays & Pointers.
When you use an array as a parameter to a function, it "decays" to a pointer to the first element of the array. Since messages is an array of pointers to char, when the array is passed to the function, it becomes a pointer to a pointer to a char. This happens even though you are specifying it as an array in your parameter list; that is just how the language works.
So in void printSize(), when you use sizeof(messages), you get the size of a pointer. You are dividing that by the size of another pointer sizeof (char*). On your system, the size of a pointer is 4 bytes in both cases, so the result you get is 4 / 4, i.e., 1.
In main(), however, your array of char* is defined as, and treated as, an array. When the sizeof() operator is applied to an array, you get the size of all the bytes in the entire array. What is this an array of? It's an array of four pointers to char. Each pointer has the size 4. So the total size of the array is 4 * 4 = 16 bytes. You are dividing this 16 by the size of a single pointer to char, which is 4. So you are getting the result 16 / 4, i.e. 4 as the answer in main().

Resources