1

Why this function works

#include <stdio.h>
#include <string.h>

void print_array(char **array, size_t size)
{
    for (int i = 0; i < size; i++) {
        printf("%s\n",array[i]);
    }
}

int main()
{

    char *base_data[] = {
        "sample 1",
        "sample 2",
        "sample 3"
    };


    print_array(base_data,sizeof(base_data)/sizeof(char*));

    return 0;
}

But this code does not

#include <stdio.h>
#include <string.h>

void print_array(char **array)
{
    for (int i = 0; i < sizeof(array)/sizeof(char*); i++) {
        printf("%s\n",array[i]);
    }
}

int main()
{

    char *base_data[] = {
        "sample 1",
        "sample 2",
        "sample 3"
    };


    print_array(base_data);

    return 0;
}

The program crashes after printing first value. No matter what I try, I am not able to find the size of the array of pointers to strings inside a function call. Most of the stackoverflow examples also pass the size of array to the functions. What happens to an array of pointers to strings when its passed to functions?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
A. Munir
  • 125
  • 4

1 Answers1

3

In the first program the expression

sizeof(base_data)

gives the size of the array declared like

char *base_data[] = {
    "sample 1",
    "sample 2",
    "sample 3"
};

In the second program the expression

sizeof(array)

gives the size of a pointer because array is a pointer according to the function declaration

void print_array(char **array);

Even if you will declare the function like

void print_array(char *array[3]);

nevertheless the compiler adjusts the declaration to the declaration

void print_array(char **array);

So the above two declarations are equivalent and declare the same one function with one parameter of a pointer type. Within the function you are dealing with a pointer.

On the other hand, an array passed to a function is implicitly converted to pointer to its first element.

You could use for example a sentinel value equal to NULL as for example

#include <stdio.h>
#include <string.h>

void print_array(char **array)
{
    while ( *array ) puts( *array++ );
}

int main( void )
{

    char *base_data[] = {
        "sample 1",
        "sample 2",
        "sample 3",
        NULL
    };


    print_array(base_data);
}

Or you need to pass explicitly the size of the array like

#include <stdio.h>
#include <string.h>

void print_array( char **array, size_t n )
{
    for ( size_t i = 0; i < n; i++ ) puts( array[i] );
}

int main( void )
{

    char *base_data[] = {
        "sample 1",
        "sample 2",
        "sample 3",
    };


    print_array(base_data, sizeof( base_data ) / sizeof( *base_data ) );
}

P.S. And the second program should not crash. It just outputs one element pointed to by the expression array[i]. Just check the value of the expression sizeof(array)/sizeof(char*) within the function like

printf( "%zu", sizeof(array)/sizeof(char*) );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • So there is no way in which you could pass an array to a function and calculate the size of the array inside that function? – A. Munir Jul 02 '19 at 18:40
  • @A.Munir See my updated post. – Vlad from Moscow Jul 02 '19 at 18:44
  • Why does while(*array) return true? If memory is not initiated is it populated with nulls? – A. Munir Jul 02 '19 at 18:53
  • @A.Munir *If memory is not initiated is it populated with nulls* : if memory is not initialized, what it is populated with is *undefined*; but if you pass a pointer to an initialized array, `while ( *array )` will be true, up to the point where `*array` evaluates to `null` -- that is, up to the point where the corresponding array element has been initialized to `null` – landru27 Jul 02 '19 at 21:00
  • @A.Munir : ... also note that sometimes memory is *auto-initialized*, but my other comment still stands, no matter who/what is doing the initialization – landru27 Jul 02 '19 at 21:01