0

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.

Community
  • 1
  • 1
Michi
  • 5,175
  • 7
  • 33
  • 58
  • Where is that duplicate Question which is based of my Question? – Michi Dec 16 '15 at 22:21
  • 2
    Try `int arr[] = {1, 2, 3, '\0', 4, 5, 6, '\0'};` and it will print 3 instead of 7, so you can see it's not actually getting the length of the array. (But if this fits your needs, it's an okay thing to do *instead of* getting the length of the array) – user253751 Dec 16 '15 at 22:22
  • 2
    Also I don't think this is a duplicate since it's not about sizeof. Voting to reopen... – user253751 Dec 16 '15 at 22:22
  • Please reopen my Question. And i did mention about that immbis, I mean I edited my Question. – Michi Dec 16 '15 at 22:24
  • 4
    You're using a *sentinel*. Note that `'\0'` is simply `0`. – Karoly Horvath Dec 16 '15 at 22:26
  • As long as the Array doesn't have `0` inside you can get the length, that is my Question – Michi Dec 16 '15 at 22:27
  • You may add second parameter to `foo( int * arr, int arr_len )` and send array length. – i486 Dec 16 '15 at 22:27
  • @i486 Really, did you read my Question? When did i Asked about that? – Michi Dec 16 '15 at 22:27
  • 3
    Looks fine to me. It's just use of a sentinel value to mark the end of the array and is not uncommon. As long as the sentinel value is outside the set of regular valid values. For example, the C standard defines that the `main` parameter, `argv`, has a NULL sentinel. And also, of course C strings are essentially char arrays with a NUL sentinel. – kaylum Dec 16 '15 at 22:27
  • Based of your Comments, should I understand that if the Array doesn't contain `0`, you can get its length ? – Michi Dec 16 '15 at 22:29
  • @KarolyHorvath I do know that, i just used `'\0'` to explain my point. – Michi Dec 16 '15 at 22:30
  • The only problem is, the function reports the length as 1 too few. `int arr1[] = {10,'\0'};` has 2 elements. – Weather Vane Dec 16 '15 at 22:31
  • @Michi Yes assuming your arrays will never contain a zero you can append one on the end as the last value and use your method to get the length. Obviously this won't work for all cases and probably isn't ideal, but for what you want to do it'll work :) – Ryan Fitzpatrick Dec 16 '15 at 22:31
  • @WeatherVane Sir, please explain – Michi Dec 16 '15 at 22:31
  • I don't understand why you need this? Is it theoretical exercise or you need such "feature"? Generally, C language does not provide such extras. It is better to add array length as first element (prefix) than marking end of array with zero. – i486 Dec 16 '15 at 22:31
  • PS: BTW, you can simply put `0` element instead of `'\0'`. – i486 Dec 16 '15 at 22:32
  • @Michi `int arr1[] = {10,'\0'};` has 2 elements, not 1. Just because you defined `\0` unusually for `int` does not make it just as much a part of the array as the other elements. – Weather Vane Dec 16 '15 at 22:32
  • @i486 I'm 35 Years old, married with two kids, `C language` is just for fun, I didn't study in school `C` or others languages. – Michi Dec 16 '15 at 22:33
  • @WeatherVane Yes, i know that, but there is no need to count it, or keep track of it. the same goes for `char arr[] = {'a', 'b', '\0'};`, the `'\0'` is there, but you don't needed. – Michi Dec 16 '15 at 22:35
  • Down Voter please Explain. I really hate you Guys for doing that with no Reason. Why SO allows this? – Michi Dec 16 '15 at 22:51
  • @Michi Why does SO allow downvoting? Why wouldn't it? Sure it's annoying when someone does it without a reason, but usually the reason is "this question isn't very useful". – user253751 Dec 16 '15 at 22:55
  • @Michi If I'd downvoted this question (which I didn't) it would probably be because it's not entirely clear what you want to know. You want to know why this works? Well that seems like an obvious answer - which is that there's nothing *stopping* it from working. – user253751 Dec 16 '15 at 22:56
  • @immibis Sir, I didn't ask about `Why does SO allow downvoting?`, I was asking why i got Down voted. – Michi Dec 16 '15 at 22:56
  • @immibis NO, the Question is clear. There are 3 Answers, and No one was disagree. – Michi Dec 16 '15 at 22:57
  • I'm feeling like someone has something against me. – Michi Dec 16 '15 at 22:58
  • !Michi "Why foo prints the length of all arrays?" is the question? It's sort of like asking why `void foo(int *p) {int len = 5; printf("%d\n", len);} int main() {int a[5]; int b[5]; int c[5]; foo(a); foo(b); foo(c); return 0;}` prints the length of all the arrays - it doesn't magically know the length of the arrays, you told it how to "find the length" (in this case, you said it's always 5) – user253751 Dec 16 '15 at 22:59
  • @immibis Probably the Question inside the Topic, at the end, wasn't exactly the 100 points one, but I think everyone here Understood it. – Michi Dec 16 '15 at 23:00
  • 1
    `void foo(int *arr)` does not get an array at all. So how would youi calculate an "array size"? A pointer is not an array. You just cannot pass an array to/from a function in C. – too honest for this site Dec 16 '15 at 23:20
  • 1
    @Olaf Sir, I do know that `arr[]` decays to a pointer. It wasn't about passing Array to Function, It was only to find its length as long as there is no `0` inside it. Was just Theory in here and nothing more. – Michi Dec 16 '15 at 23:26
  • The same thing [Here](http://stackoverflow.com/questions/33231470/how-to-find-actual-end-of-char-array-in-c-containing-zeros-in-the-middle/33232025#33232025) was just a Theory, but it works at some point. – Michi Dec 16 '15 at 23:29
  • You son't even have `int arr[]`. I just comment on the title, which is completely missleading. And finding a specific value in an array is something you can find in every C book or tutorial. Effectively you ask if an _integer character constant_ can be converted to `int`. But it **is** actually an [`int`](http://port70.net/~nsz/c/c11/n1570.html#6.4.4.4p10). – too honest for this site Dec 16 '15 at 23:40
  • However, it is bad style. Use a macro with a constant integer similar to `EOF`. – too honest for this site Dec 16 '15 at 23:47
  • @Olaf Thank you for your time, like always strait to the language. – Michi Dec 16 '15 at 23:51
  • @Olaf Is there anyway to separate `0` from `'\0'` in C? To write a code that it doesn't compare `'\0'` with `0` being the same, – Michi Dec 16 '15 at 23:58
  • @Michi: I stated that clear in my comment (and provided even a link to the standard. But compliant does not imply "good style". – too honest for this site Dec 17 '15 at 00:09
  • @Olaf Oh, Sorry about that, is 01:10, i didn't saw that. :D – Michi Dec 17 '15 at 00:11
  • @Michi Nope, because they're the same thing written differently. – user253751 Dec 17 '15 at 00:29
  • Down voter please explain – Michi Dec 19 '15 at 23:44

4 Answers4

4

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.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • I'm 100% sure that I will never use my Program Example in some code, but there was only theory for future explanations for me- – Michi Dec 16 '15 at 22:39
  • I understand. But I thought I would cover *why* such an approach is not a good idea for anyone reading this now/later. – P.P Dec 16 '15 at 22:41
  • Yes, but based on my Question and on your Answer and others Answer, this makes a valid way to find Array length, or not?...as long as the Array doesn't contain `0`! – Michi Dec 16 '15 at 22:43
  • Thank you, this is What i needed and this was the Answer I needed for my Question. – Michi Dec 16 '15 at 22:44
4

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.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
2

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.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
1

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 ;
    }
}
Community
  • 1
  • 1
  • Thank you for your explanation. I do understand it, but this does'n Answer My Question. I do not try to find a way how to do it, I already know that, +1 for that. – Michi Dec 16 '15 at 23:33
  • I am not a fan of sentinels at the end of arrays. In C strings they are fine as it's the standard and code expects it. But to find the length of an array you have to read every single element, which is not efficient. Placing the length at the front or keeping it in a struct or separate variable is much more efficient, IMO. Knowing the length in this way also means you can implement e.g. linear searches on sorted arrays. Another variation is to store the length *and* a hashcode for a string or the data to speed up comparisons. – StephenG - Help Ukraine Dec 16 '15 at 23:39
  • this is one of the reason why i hate `c` (even if i like the languagfe :) ), because `0` and `'\0'` are treated the same – Michi Dec 16 '15 at 23:55
  • In fact they are *not* treated the same. The digit `0` will be treated as a zero digit for any numerical type. It s sometimes even used instead of `NULL` as a null pointer value ( which is bad practice, IMO ). However `'\0'` is **not** a digit, it's a *char* of value zero. Now C will do some conversions between integer types for you, but sometimes it will find that the char value clashes with it's rules. So be aware they are not the same in a strict sense. – StephenG - Help Ukraine Dec 17 '15 at 00:03
  • Sir, again, please stick to my Question/comments here `'\0'` and `0` are the same. This was my point. – Michi Dec 17 '15 at 00:06
  • My point is that it is bad programming practice to use them as if they were interchangeable. I'm suggesting you get out of the habit of thinking they are. If C bothers you I'd suggest you consider C# or maybe D or Vala. Why use something that irritates you when there are so many choices ? – StephenG - Help Ukraine Dec 17 '15 at 00:19