-1

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.

  • 4
    1) a pointer is no array is no pointer. 2) Your compiler wants to cry, enable warnings! 3) `NULL` is not (well, should not be) an integer 4) (Re-)read the chapter about pointers and arrays in a good C book. 5) "My code does not work" is not a **specific** problem description. – too honest for this site Oct 31 '15 at 23:53
  • 1
    Possible duplicate of [How to find the 'sizeof'(a pointer pointing to an array)?](http://stackoverflow.com/questions/492384/how-to-find-the-sizeofa-pointer-pointing-to-an-array) – Bo Persson Nov 01 '15 at 05:44
  • I've marked this question down and voted for closure. The OP is asking for help debugging. Also, it appears that all replies are being written down for providing realistic answers, since they don't meet the OP's unrealistic requirement "I don't want to send the size value like a function parameter". – Peter Nov 01 '15 at 08:18
  • @Peter: As I understood it, OP wants to avoid having a separate function argument for the size, which is different from having to manually track the size in a variable. I think my proposal of including this variable in a `struct` and using the `struct` as an "array object" with built-in length would meet the OP's requirement. – code_dredd Nov 01 '15 at 08:26
  • An instance of a struct is still a variable, ray - just one of a different type. The pattern of downvoting of replies (which I didn't do, BTW) suggests replies are being held to an impossible standard. There is no means in C to obtain the size of an array within a function when only a pointer (to the first element) is passed. The replies attempt to provide alternatives to pass the length information (or use a sentinel), which are realistic but do not meet the requirement. – Peter Nov 01 '15 at 08:42
  • @Peter: The only thing OP wanted was to avoid a separate argument to a function, not to calculate length from a pointer. – code_dredd Nov 01 '15 at 22:06

3 Answers3

0

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.

code_dredd
  • 5,915
  • 1
  • 25
  • 53
  • @101010: The code-base does not get "obfuscated" by defining a more abstracted data type. (Otherwise, where would O-O languages be today?) Your simpler solution has problems of its own, like being more difficult to maintain in the long-term. – code_dredd Nov 01 '15 at 01:37
  • @101010: Also, the overhead for the dereference is negligible. Whether the array has been `malloc`ed dynamically or not is irrelevant and the OP can certainly do whatever he wants ther (it was an *example*). Based on your reasoning, it'd be impossible to solve the OP's problem because, to keep track of the length, we either have to send the argument separately as you suggest (which the OP does *not* want to do), or we can put it into a structure to avoid that. The OP said nothing about not wanting to use a struct, so there's nothing wrong with that proposal. – code_dredd Nov 01 '15 at 01:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93893/discussion-between-ray-and-101010). – code_dredd Nov 01 '15 at 01:39
-1

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.

lost_in_the_source
  • 10,998
  • 9
  • 46
  • 75
  • I think this proposed solution creates additional problems, including code that's more difficult to maintain, understand, and debug --particularly for non-trivial programs. It also prevents otherwise OK values from being valid entries in the list (e.g. -1). You admit this in your post, yet you still make the recommendation. Since the OP has admitted to being a beginner, I think this will create more issues in the long term, IMHO. – code_dredd Nov 01 '15 at 00:18
  • Also, there's the issue of this not providing the *length* of the array, which is what the OP wants to keep track of without passing it around separately. Instead, you'd have to calculate the length each time by looping until the sentinel is found, which is slower than the O(1) alternative. – code_dredd Nov 01 '15 at 00:36
  • I never recommended the sentinel approach. I was just answering the OP's question. It's up to him to decide whether he wants this solution or not. @ray – lost_in_the_source Nov 01 '15 at 12:44
-3
#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)

BIG_FAN
  • 1
  • 3
  • 1
    This does not work because `*a` points to a `short` in `sizeof(*a)` and you divide that by `sizeof(short)` so it can never go through the entire array. Instead, it always prints the first element, which was already reachable by `*a` – code_dredd Nov 01 '15 at 02:00