C/C++:sizeof arrays and pointers

Posted by DeadEvil on Tue, 09 Jul 2019 02:36:06 +0200

C/C++:sizeof arrays and pointers

Using sizeof in C/C++ yields different results for arrays and pointers.

[example 1]

#include <stdio.h>
#include <stdlib.h>

#define SAFE_FREE(p) {free(p);p=NULL;}

int main()
{
    char arr[20];
    char *p = (char *)malloc(sizeof(char) * 20);
    printf("sizeof arr :%d\n", sizeof(arr));
    printf("sizeof p :%d\n", sizeof(p));

    SAFE_FREE(p);   

    return 0;
}

Output:

[test1280@localhost 20170416]$ ./main
sizeof arr :20
sizeof p :4

A variable sizeof gets the number of bytes occupied by that variable.

Using sizeof to operate on an array (sizeof is an operator, not a function), you get the number of bytes of memory occupied by the array.

It's possible to think that if you use sizeof to operate on a pointer, you will get the number of bytes occupied by the space pointed to by the pointer.

Not at all!

What is the pointer? Pointer is a variable, since it is a variable, then you sizeof a pointer variable, the result of course is the number of bytes occupied by this pointer variable.

What does a pointer variable do? To identify an address, the address is globally unique throughout the computer.

If the computer has 32 address lines at most addressing 4G, can you uniquely identify it with a 16-bit variable? Obviously not.

The size of a pointer variable is not only related to the hardware and operating system of the computer itself, but also to your compiler.

It's entirely possible that a pointer variable compiled by the compiler on a 64-bit computer occupies 4 bytes.

Note: All the following experiments are based on the following environments:

[test1280@localhost 20170416]$ uname -a
Linux localhost.localdomain 2.6.32-431.el6.i686 #1 SMP Fri Nov 22 00:26:36 UTC 2013 i686 i686 i386 GNU/Linux
[test1280@localhost 20170416]$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
Copyright (C) 2010 Free Software Foundation, Inc.

Example 1 illustrates:

Array names and pointer variables are different, although they can access variables / arrays through [] or *.

When a pointer variable is operated with sizeof, the result is always the size of the pointer variable itself, not the size of the space pointed by the pointer variable.

[example 2]

#include <stdio.h>
#include <stdlib.h>

#define SAFE_FREE(p) {free(p);p=NULL;}

void foo(char arr[], char *p) 
{
    printf("sizeof arr :%d\n", sizeof(arr));
    printf("sizeof p :%d\n", sizeof(p));
}

int main()
{
    char arr[20];
    char *p = (char *)malloc(sizeof(char) * 20);

    foo(arr, p); 

    SAFE_FREE(p);   

    return 0;
}

The output results are as follows:

[test1280@localhost 20170416]$ ./main 
sizeof arr :4
sizeof p :4

Conclusion:

When an array is passed as a parameter in a function call, it degenerates into a pointer inside the called function. Using sizeof is equivalent to sizeof a pointer variable, the size of which is the memory space occupied by a pointer variable.

Usually we can see that one parameter is of array type, or pointer type. It contains another parameter, which is an integer value to identify the size of the array type (pointer type), because the size of the called function is unknown.

Here's sizeof.

sizeof is an operator, not a function, and its return value is size_t type.

sizeof is compiled, that is, the size of its value is determined before it runs, unlike function calls, which are determined during the run.

The object of sizeof can be either a type or a variable.

#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("%d\n", sizeof(char));
    printf("%d\n", sizeof(int));

    char c;
    int i;

    printf("%d\n", sizeof(c));
    printf("%d\n", sizeof(i));

    printf("%d\n", sizeof c); 
    printf("%d\n", sizeof i); 

    return 0;
}

Compile and run all OK.

Note the following procedure:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("%d\n", sizeof char);
    printf("%d\n", sizeof int);

    return 0;
}

Compile error:

[test1280@localhost 20170416]$ gcc -o main main.c -Wall
main.c: In function 'main':
main.c:6: error: expected expression before 'char'
main.c:7: error: expected expression before 'int'

Summary:

There are three correct ways to use sizeof:

sizeof(type_name);
sizeof(var);
sizeof var;

But sizeof type_name is wrong.

Recommendations:

When using sizeof, brackets should be added to the uniformity.

[example 3]

#include <stdio.h>
#include <stdlib.h>

int main()
{

    int n = 0;
    printf("%d\n", sizeof(n=100));
    printf("%d\n", n); 

    return 0;
}

Output:

[test1280@localhost 20170416]$ !g
gcc -o main main.c -Wall
[test1280@localhost 20170416]$ ./main
4
0

Why is the output zero? The key is that sizeof is defined at the compilation stage. The expression:

n = 100

This is an assignment expression, and the operator = returns the type of the left operand, which is int.

So, after compilation, before running, it's actually equivalent to output sizeof(int).

Because sizeof can't be compiled into machine code, the content in the scope of sizeof, that is, () can't be compiled, but can be replaced by type.

[example 4]

#include <stdio.h>
#include <stdlib.h>

char char_f(){return 'a';}
int int_f(){return 0;} 
double double_f(){return 0;} 
void void_f(){}

int main()
{

    printf("%d\n", sizeof(char_f()));
    printf("%d\n", sizeof(int_f()));
    printf("%d\n", sizeof(double_f()));
    printf("%d\n", sizeof(void_f())); 

    printf("\n");

    printf("%d\n", sizeof(void));

    printf("\n");

    printf("%d\n", sizeof(char_f));
    printf("%d\n", sizeof(int_f));
    printf("%d\n", sizeof(double_f));
    printf("%d\n", sizeof(void_f));

    return 0;
}

Output:

[test1280@localhost 20170416]$ !g
gcc -o main main.c -Wall
[test1280@localhost 20170416]$ ./main
1
4
8
1

1

1
1
1
1
[test1280@localhost 20170416]$ 

First of all, the first four are well understood, sizeof returns the size of the type of return value of each function.
For void, using sizeof yields 1;
At the end of the four 1 I can not explain for the time being, to be explained in the future, or have friends to help me explain ~Thank you!~
(Note: Function name is just a symbol, representing an address, should also be 4, why 1?)

[example 5]

#include <stdio.h>
#include <stdlib.h>

int main()
{
    double* (*a)[3][6];

    printf("%d\n", sizeof(a));      //4 
    printf("%d\n", sizeof(*a));     //3*6*4
    printf("%d\n", sizeof(**a));    //6*4
    printf("%d\n", sizeof(***a));   //4 
    printf("%d\n", sizeof(****a));  //8 

    char arr[5][8];
    printf("%d\n", sizeof(*arr));   //8 

    return 0;
}

Output:

[test1280@localhost 20170416]$ !g
gcc -o main main.c
[test1280@localhost 20170416]$ ./main
4
72
24
4
8
8

Explanation of Example 5:

What is a? A is first a pointer, similar to int (*a);

So sizeof(a) is equivalent to sizeof(char *), or 4 (maybe 8);

What kind of data does this pointer point to?
Comparing int (a) to point to an int type of data, it is not difficult to understand that a here points to a double*[3][6] type of data;

So * a represents such a data entity, in which each element is a pointer to a double object. How many pointers are there? 3*6 = 18. How big is each pointer? 4 bytes, so the result is 3 * 6 * 4 = 72;

** a is equivalent in meaning to * arr;

arr is a pointer to an array, which is at the array level.
* arr is a pointer to a row in an array, which is row level.
** arr is a pointer to an element in an array, at the element level.

The sizeof(arr) result is the size of all elements in a row, that is, the number of elements in a row and the size of each element, so the sizeof(*arr) result is 8*1=8.

Looking back at the ** arr here, the result is naturally 6 * 4 = 24.

*** arr has been said above, this is a specific object, then the specific object is a double type pointer, so it is 4 (or 8);

What is the type of **** arr? It's a double type, and the result is 8.

That's basically what I understand.

Well, finally, let's look at a simple little program:

[example 6]

#include <stdio.h>
#include <stdlib.h>

#define ARRAY_SIZE(arr, type_name) (sizeof(arr)/sizeof(type_name))

int main()
{
    char arr[] = "abcdef";
    char *p = arr;

    printf("%d\n", sizeof(arr));  //7 
    printf("%d\n", sizeof(p));    //4 

    // How to get the array size (in elements)
    int array[] = {1, 2, 3, 4, 5, 6}; 
    printf("%d\n", ARRAY_SIZE(array, int));

    char s[2048] = "abcdefgh";
    // Output 2048. Initialization is initialization. If the size of the array has been determined, it will not affect the size of the array, not 9.
    printf("%d\n", sizeof(s));

    return 0;
}

Output:

[test1280@localhost 20170416]$ gcc -o main main.c
[test1280@localhost 20170416]$ ./main
7
4
6
2048

It's worth noting that we use a macro to find the size of an array.

However, it is also a prerequisite that the size of the recognizable array (when the size of the array is correct) is established, after all, macros are only a replacement.

Reference sources:

1.http://blog.csdn.net/luguifang2011/article/details/39988627
2.http://blog.csdn.net/kangroger/article/details/20653255
3.http://www.cnblogs.com/qingergege/p/5943764.html

Topics: Linux Red Hat