Using ternary and summing array

Discussion in 'C Programming' started by flebber, Oct 31, 2011.

  1. flebber

    flebber Guest

    Hi

    I am learning C. I am trying to sum an array with the values returned
    from a loop. Can I use the "?" operator as part of a loop; by
    experimentation I know I can't put the increment in the loop.

    doing ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :i++ ; never actually
    finished, I think I created an infinite loop.
    PS I was following the example from here
    http://www.tutorialspoint.com/ansi_c/ternary_operator_examples.htm

    So I have come to this this solution, I think the problem is that my
    array a[] is assigned as a one element array and since the first value
    returns false it gets 0 and exits. Is this right? If it is how do i
    assign an array to have an unknown number of entries?

    A kick in the right direction appreciated

    #include <stdio.h>
    int a[],i,sum=0;

    int main()
    {
    while(i < 1000)
    {
    ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :0 ;
    i++;
    }
    printf("The sum is %d\n",sum);
    return 0;
    }


    Sayth
     
    flebber, Oct 31, 2011
    #1
    1. Advertising

  2. flebber

    flebber Guest

    On Oct 31, 9:35 pm, flebber <> wrote:
    > Hi
    >
    > I am learning C. I am trying to sum an array with the values returned
    > from a loop. Can I use the "?" operator as part of a loop; by
    > experimentation I know I can't put the increment in the loop.
    >
    > doing ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :i++ ; never actually
    > finished, I think I created an infinite loop.
    > PS I was following the example from herehttp://www.tutorialspoint.com/ansi_c/ternary_operator_examples.htm
    >
    > So I have come to this this solution, I think the problem is that my
    > array a[] is assigned as a one element array and since the first value
    > returns false it gets 0 and exits. Is this right? If it is how do i
    > assign an array to have an unknown number of entries?
    >
    > A kick in the right direction appreciated
    >
    > #include <stdio.h>
    > int a[],i,sum=0;
    >
    > int main()
    > {
    >   while(i < 1000)
    >   {
    >     ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :0 ;
    >     i++;
    >   }
    >   printf("The sum is %d\n",sum);
    >   return 0;
    >
    > }
    >
    > Sayth


    Well I solved it using an if statement, but I would still love to know
    if there is a way to do it with the "?".

    Working Solution


    #include <stdio.h>
    int i,sum=0;
    int total;

    int main()
    {
    while(i < 1000)
    {
    if ((i % 3 == 0)||(i % 5 == 0)){
    sum += i;
    }
    i++;
    }
    printf("The sum is %d\n",sum);
    return 0;
    }

    Cheers

    Sayth
     
    flebber, Oct 31, 2011
    #2
    1. Advertising

  3. flebber

    flebber Guest

    On Oct 31, 9:35 pm, flebber <> wrote:
    > Hi
    >
    > I am learning C. I am trying to sum an array with the values returned
    > from a loop. Can I use the "?" operator as part of a loop; by
    > experimentation I know I can't put the increment in the loop.
    >
    > doing ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :i++ ; never actually
    > finished, I think I created an infinite loop.
    > PS I was following the example from herehttp://www.tutorialspoint.com/ansi_c/ternary_operator_examples.htm
    >
    > So I have come to this this solution, I think the problem is that my
    > array a[] is assigned as a one element array and since the first value
    > returns false it gets 0 and exits. Is this right? If it is how do i
    > assign an array to have an unknown number of entries?
    >
    > A kick in the right direction appreciated
    >
    > #include <stdio.h>
    > int a[],i,sum=0;
    >
    > int main()
    > {
    >   while(i < 1000)
    >   {
    >     ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :0 ;
    >     i++;
    >   }
    >   printf("The sum is %d\n",sum);
    >   return 0;
    >
    > }
    >
    > Sayth


    I created a working solution with an if statement but I would still
    really love to know if I could use the "?" to acheive the same result.

    Working solution


    #include <stdio.h>
    int i,sum=0;
    int total;

    int main()
    {
    while(i < 1000)
    {
    if ((i % 3 == 0)||(i % 5 == 0)){
    sum += i;
    }
    i++;
    }
    printf("The sum is %d\n",sum);
    return 0;
    }


    Sayth
     
    flebber, Oct 31, 2011
    #3
  4. On 31 oct, 11:35, flebber

    > #include <stdio.h>
    > int a[],i,sum=0;


    'a' size is undefined.

    > int main()
    > {
    > while(i < 1000)


    'i' is not initialized.

    > {
    > ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :0 ;


    1) You can't just write (a)?b:c;
    2) 'a' is not initialized.

    > i++;
    > }
    > printf("The sum is %d\n",sum);
    > return 0;
    > }


    ----

    If you really want to use (a)?b:c; I suggest

    #define SIZE 1000
    int main(void)
    {
    int a[SIZE], i, sum;

    // here you must initialize 'a' values
    // ...

    // loop
    for( sum=i=0; i < SIZE; ++i )
    sum += ( !(i % 3) || !(i % 5) ) ? a : 0;

    printf("The sum is %d\n",sum);
    return 0;
    }

    ----

    Now, since it's pointless adding sum+=0 you could

    for( sum=i=0; i < SIZE; ++i )
    if( !(i % 3) || !(i % 5) ) sum += a;

    Anyway, what are the 1000 values of a ?
     
    Jean-Christophe, Oct 31, 2011
    #4
  5. flebber

    James Kuyper Guest

    On 10/31/2011 06:35 AM, flebber wrote:
    > Hi
    >
    > I am learning C. I am trying to sum an array with the values returned
    > from a loop. Can I use the "?" operator as part of a loop; by
    > experimentation I know I can't put the increment in the loop.
    >
    > doing ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :i++ ; never actually
    > finished, I think I created an infinite loop.


    You can put the increment in the loop, and you did so in the code below.
    What you shouldn't do is put it in a conditional part of the ternary
    expression. Your loop's behavior depends only upon the value of 'i'. If,
    during one pass though the loop, the value of i doesn't change, it will
    go through the loop again, with the same value of i, and therefore
    exactly the same behavior - which means it still won't change. Infinite
    loop.

    Now, with that in mind, take a look at the code above. If i has a value
    which is a multiple of 3 or a multiple of 5, the value of i will not be
    changed.

    That's why you've got to move the i++ out of the ternary expression, as
    you did in your code below.

    > PS I was following the example from here
    > http://www.tutorialspoint.com/ansi_c/ternary_operator_examples.htm
    >
    > So I have come to this this solution, I think the problem is that my
    > array a[] is assigned as a one element array and since the first value
    > returns false it gets 0 and exits. Is this right? ...


    No, the first value does not "return false". Your code attempts to read
    the first 1000 elements of a[], regardless of whether or not it actually
    has 1000 elements. So what happens is that it tries to read pieces of
    memory that aren't actually part of a[]. As a result, the behavior of
    your program is not defined by the C standard. This is bad - very bad.
    Don't do that.

    > ... If it is how do i
    > assign an array to have an unknown number of entries?


    You can never assign an array - what you actually mean, I think, is
    either "define" or "declare".

    You can't define an array to have an unknown number of entries. Defining
    an object requires you to give the compiler all the information it needs
    to set aside storage space for the object; if you don't tell it how long
    the array is, the compiler can't do that. When you declared it as int
    a[], and didn't provide an actual length anywhere else in your program,
    it implicitly made the length 1. But that's something you should have
    known; it doesn't count as defining an array of unknown length.

    What you can do is declare an array to have a number of entries that is
    not known within your code, but is known SOMEWHERE ELSE. For instance,
    the simplest change to your code that would allow this is to declare

    extern int a[];

    In some other part of your program, you must provide a definition for a
    that does have a specific length:

    int a[1000];

    However, using global variables is seldom the best solution. All of your
    variables are global, and none of them should be. A more appropriate way
    to do this would be to declare a function, which takes a pointer to the
    first element of the array, and length:

    int three_five_sum(
    int a[],
    int n
    ){
    // body of function.
    }

    That looks like it defines a to be an array, but one of the confusing
    features of C is that the declaration of an array as a parameter to a
    function is automatically converted into a declaration of a pointer to
    the element type of that array. It's exactly the same as if I had
    written "int *a". Just as a matter of convention, I normally declare
    parameters which are pointers to the first element of an array using
    array[], while I write those which are pointers to a single object as
    *single_object. As far as I can tell, this convention is my own
    peculiarity, and not in wide use.

    > A kick in the right direction appreciated
    >
    > #include <stdio.h>
    > int a[],i,sum=0;
    >
    > int main()
    > {
    > while(i < 1000)
    > {
    > ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :0 ;
    > i++;
    > }
    > printf("The sum is %d\n",sum);
    > return 0;
    > }


    There are many good uses of the ternary operator; I use it all the time.
    This isn't one of them. An expression statement containing a ternary
    expression can usually be re-written using if(). Unless you're using the
    result of the ternary expression, it's generally better to use the if()
    version:

    if( i%3 == 0 || i%5 == 0)
    sum += a;

    Of course, the whole point of your exercise was to practice the use of
    the ternary operator - but you should do that with a problem for which
    that operator is a reasonable thing to use. Try the following: write a
    function that takes two pointer arguments, a and b, and a count. For
    each value of i from 0 to count-1, it adds something to sum. However, if
    i is a multiple of 3 or 5, it adds a to sum; otherwise, it adds b
    to sum.

    You've got a variable named i, which is used only inside the loop, which
    must be incremented during each step of the loop. When you've got that
    combination, it's generally better to write it as a for() loop rather
    than a while loop:

    for(int i=0; i<1000; i++)

    If your code has to be compatible with C90, you'll have to break that up
    into two parts:

    int i;
    for(i=0; i<1000; i++)

    --
    James Kuyper
     
    James Kuyper, Oct 31, 2011
    #5
  6. Jean-Christophe <> writes:

    > On 31 oct, 11:35, flebber
    >
    >> #include <stdio.h>
    >> int a[],i,sum=0;

    >
    > 'a' size is undefined.
    >
    >> int main()
    >> {
    >> while(i < 1000)

    >
    > 'i' is not initialized.


    It is. It's got static storage duration and hence will be zero
    initialised. It should not be "out there" and, if it were defined where
    it should be, (in main) you'd be right.

    >> {
    >> ((i % 3 == 0)||(i % 5 == 0)) ? sum+=a :0 ;

    >
    > 1) You can't just write (a)?b:c;


    I know what you mean -- it's not a good idea -- but it's perfectly valid
    C.

    > 2) 'a' is not initialized.


    It is. Both 'i' and 'a' are initialised in the op's code. That 'a' is
    both defined and initialised is an odd quirk of C and that quirk should
    definitely not be used by anyone.

    >> i++;
    >> }
    >> printf("The sum is %d\n",sum);
    >> return 0;
    >> }


    <snip>
    --
    Ben.
     
    Ben Bacarisse, Oct 31, 2011
    #6
  7. flebber <> writes:
    <snip>
    > On Oct 31, 9:35 pm, flebber <> wrote:
    > I created a working solution with an if statement but I would still
    > really love to know if I could use the "?" to acheive the same result.


    Yes, but it won't be any clearer.

    > Working solution
    >
    >
    > #include <stdio.h>
    > int i,sum=0;
    > int total;


    You don't use total. It will just confuse people.

    > int main()
    > {
    > while(i < 1000)
    > {
    > if ((i % 3 == 0)||(i % 5 == 0)){
    > sum += i;


    You can write

    sum += (i % 3 == 0 || i % 5 == 0) ? i : 0;

    Since logical expressions are either 0 or 1, you can also write

    sum += (i % 3 == 0 || i % 5 == 0) * i;

    but both are, in my opinion, inferior to a simple 'if'.

    What would make it clearer is to use a 'for' loop and to avoid having
    "global" (technically file scope) variales. Simple counted loops are
    best expressed using 'for'.

    > }
    > i++;
    > }
    > printf("The sum is %d\n",sum);
    > return 0;
    > }


    --
    Ben.
     
    Ben Bacarisse, Oct 31, 2011
    #7
  8. flebber

    flebber Guest


    > If you really want to use (a)?b:c; I suggest
    >
    > #define SIZE 1000
    > int main(void)
    > {
    > int a[SIZE],  i,  sum;
    >
    > // here you must initialize 'a' values
    > // ...
    >
    > // loop
    >  for( sum=i=0;  i < SIZE;  ++i )
    >   sum += ( !(i % 3) || !(i % 5) ) ? a : 0;
    >
    >  printf("The sum is %d\n",sum);
    >  return 0;


    Thank You Jean-Christophe, I like the way you use the define as I
    think it makes it clear and readable.

    > No, the first value does not "return false". Your code attempts to read
    > the first 1000 elements of a[], regardless of whether or not it actually
    > has 1000 elements. So what happens is that it tries to read pieces of
    > memory that aren't actually part of a[]. As a result, the behavior of
    > your program is not defined by the C standard. This is bad - very bad.
    > Don't do that.


    James thanks for explaining that. I had the feeling I was doing it
    wrong but wasn't quite sure where it was going wrong.

    > extern int a[];


    So this declares my array as a global value. I can then assign a
    value(size of array) to it locally. This would then mean that if I had
    5 different functions they could all have their own size declared of
    array a[] locally? May not be the best idea but I could do this?

    > int three_five_sum(
    > int a[],
    > int n
    > ){
    > // body of function.
    > }


    With this skeleton shouldn't I declare int a[1000], ?

    > Try the following: write a
    > function that takes two pointer arguments, a and b, and a count. For
    > each value of i from 0 to count-1, it adds something to sum. However, if
    > i is a multiple of 3 or 5, it adds a to sum; otherwise, it adds b
    > to sum.


    Working on it... not close yet but will get there, having issues with
    local variables.

    #include <stdio.h>
    #define limit 1000;

    int two_pointer_args(int, int); /* function using two ints */
    int main()

    {
    two_pointer_args(int i, int j);
    i, j = 0;
    int i_total=0;
    int j_total=0;
    {
    while (i < limit)
    {
    if ((i % 3 == 0)|| (i % 5 == 0))
    {
    i_total+=i;
    }
    else
    {
    j_total = i + j;
    }
    i++;
    }
    printf(" The sum of i was %d and the sum of j was %d\n", i_total,
    j_total);
    }
    return 0;
    }

    Thanks for all the help Sayth.
     
    flebber, Oct 31, 2011
    #8
  9. flebber

    James Kuyper Guest

    On 10/31/2011 07:11 PM, flebber wrote:
    ....
    >> extern int a[];

    >
    > So this declares my array as a global value. I can then assign a
    > value(size of array) to it locally.


    No, that declaration REQUIRES that 'a' be a global variable. You can
    define it as a global variable in some other module, but you can never
    assign it; C doesn't allow assignment of arrays. Once you've defined the
    array, you can then assign values to each element of the array, separately.

    > ... This would then mean that if I had
    > 5 different functions they could all have their own size declared of
    > array a[] locally? May not be the best idea but I could do this?


    No, only the definition of 'a' can give it a size, and the size that it
    is given by the definition is the one and only correct size for that
    array. You can declare 'a' in multiple different modules, none of which
    know the size, but you need to make sure that none of those modules try
    to use a part of the array that doesn't exist.

    >> int three_five_sum(
    >> int a[],
    >> int n
    >> ){
    >> // body of function.
    >> }

    >
    > With this skeleton shouldn't I declare int a[1000], ?


    You need to either define or dynamically allocate an array of at least n
    ints, somewhere, but that array doesn't need to be defined with a name
    of 'a'. 'a' is simply the name of a local pointer variable that is
    initialized with a copy of the pointer value passed to three_five_sum()
    as it's first argument. Example:

    int main(void)
    {
    int bunny[256];

    // Fill in values for bunny

    // Calculate the sum for the middle 128 elements of bunny:
    int sum = three_five_sum(bunny+64, 128);

    // rest of program
    }


    >> Try the following: write a
    >> function that takes two pointer arguments, a and b, and a count. For
    >> each value of i from 0 to count-1, it adds something to sum. However, if
    >> i is a multiple of 3 or 5, it adds a to sum; otherwise, it adds b
    >> to sum.

    >
    > Working on it... not close yet but will get there, having issues with
    > local variables.
    >
    > #include <stdio.h>
    > #define limit 1000;
    >
    > int two_pointer_args(int, int); /* function using two ints */
    > int main()
    >
    > {
    > two_pointer_args(int i, int j);


    This declares a function named two_pointer_args which takes two
    arguments, both of which are integers, not pointers.

    Contrary to what I think you were trying to do, the lines after this are
    NOT interpreted as a definition of that function. First of all, the ';'
    terminates the declaration, so everything after this point is part of
    the main() function body, and has nothing to do with two_pointer_args().
    Secondly, even if you had left out the ';', it wouldn't have worked. You
    can declare the function within main() (though I think it's better to
    declare it outside of main()), and you can call it from main(), but you
    cannot define it inside main(); you have to define it somewhere else.

    > i, j = 0;


    That line does not do what you think it does. It retrieves the value of
    'i', and then discards it. Then it sets j to 0. Read up on the comma
    operator.

    > int i_total=0;
    > int j_total=0;


    You're calculating two different totals. I was talking about calculating
    a single total.

    > {
    > while (i < limit)
    > {
    > if ((i % 3 == 0)|| (i % 5 == 0))
    > {
    > i_total+=i;
    > }
    > else
    > {
    > j_total = i + j;
    > }


    The whole point of my suggestion was to create an example where it would
    be natural to use the ?: ternary operator. If you had only one variable,
    named 'total', and if you had declared the arguments as pointers named a
    and b, then you could have written:

    if( i%3 == 0 || i%5 == 0)
    total += a;
    else
    total += b;

    Now, that code can be re-written to use the ?: operator, and it's a very
    natural thing to do. Figure out how, and you'll have a much better
    understanding of what that operator is all about.

    --
    James Kuyper
     
    James Kuyper, Nov 1, 2011
    #9
  10. pete <> writes:
    > flebber wrote:
    >> I created a working solution with an if statement but I would still
    >> really love to know if I could use the "?" to acheive the same result.

    >
    >> if ((i % 3 == 0)||(i % 5 == 0)){
    >> sum += i;
    >> }

    >
    > If that is truly your goal:
    >
    > sum += ((i % 3 == 0)||(i % 5 == 0)) ? i : 0;


    Yes, but frankly it's a foolish goal. The "if" form is easier to
    read -- though personally I'd find it even easier with more whitespace
    and fewer parentheses:

    if (i % 3 == 0 || i % 5 == 0) {
    sum += i;
    }

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 1, 2011
    #10
  11. flebber

    Kaz Kylheku Guest

    On 2011-11-03, Kenneth Brody <> wrote:
    > Note that my compiler creates a[] with zero members.
    >
    > However, my compiler acts "strange" on this point.
    >
    >==========
    > #include <stdio.h>
    >
    > int a[];
    >
    > int main(void)
    > {
    > printf("%ld\n",(long)sizeof(a));
    > }
    >==========


    Do you have some tools so you see what the size of a is in the translated
    object file? (Is it in the object file?)

    This might be a degenerate case which has no meaning due to a possible flaw in
    the standard.

    Under 6.9.2 we have this text:

    A declaration of an identifier for an object that has file scope without an
    initializer, and without a storage-class specifier or with the storage-class
    specifier static, constitutes a tentative definition. If a translation unit
    contains one or more tentative definitions for an identifier, and the
    translation unit contains no external definition for that identifier, then the
    behavior is exactly as if the translation unit contains a file scope
    declaration of that identifier, with the composite type as of the end of the
    translation unit, with an initializer equal to 0.

    But an array cannot have an initializer equal to 0:

    int a[] = 0; // invalid!

    The second example for this section states the intent:

    If at the end of the translation unit containing
    int i[];
    the array i still has incomplete type, the implicit initializer causes it to
    have one element, which is set to zero on program startup.

    This would be the case if the implicit initializer were { 0 }. The intent
    is clear from the example, but for the text to bear it out, we have to
    believe that "an initializer equal to zero" refers to a specific choice
    of initializer such as { 0 }.

    > Further investigation shows that my compiler seems to treat "int a[];" the
    > same as "extern int a[];". Is that "legal"?


    I would avoid this situation, since only a non-normative example gives it
    a clear meaning.

    Compiler writers, however, should pay careful attention to examples and
    footnotes.

    What does your compiler do if, at the end of the translation unit, you
    add:

    int a[] = { 0 };

    ?
     
    Kaz Kylheku, Nov 3, 2011
    #11
  12. On Mon, 31 Oct 2011 07:46:25 -0400, James Kuyper
    <> wrote:
    <snip>
    > int three_five_sum(
    > int a[],
    > int n
    > ){
    > // body of function.
    > }
    >
    > That looks like it defines a to be an array, but one of the confusing
    > features of C is that the declaration of an array as a parameter to a
    > function is automatically converted into a declaration of a pointer to
    > the element type of that array. It's exactly the same as if I had
    > written "int *a". Just as a matter of convention, I normally declare
    > parameters which are pointers to the first element of an array using
    > array[], while I write those which are pointers to a single object as
    > *single_object. As far as I can tell, this convention is my own
    > peculiarity, and not in wide use.
    >

    FWIW, I do the same when I get to choose the style.
    Two is still far short of demonstrating wide use, though.

    Further, if I can express simply enough the actual size expected or
    used, I make it a comment:

    void interdigitate_a_flooby (flooby * x);

    void pair_items (left a [/*n*/], const right b [/*n*/], size_t n);
    /* this one could be VLAs in C99 if change order */

    void grommetize_blorbs (blorb b [/*g_min_blorb+tan(2pi)*/]);
    /* ignore the global behind the curtain */
     
    David Thompson, Nov 21, 2011
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alf P. Steinbach
    Replies:
    2
    Views:
    538
    Chris Theis
    Feb 5, 2004
  2. Yaroslav Bulatov

    Microbenchmark: Summing over array of doubles

    Yaroslav Bulatov, Aug 1, 2004, in forum: Python
    Replies:
    9
    Views:
    401
    Christopher T King
    Aug 3, 2004
  3. RS
    Replies:
    1
    Views:
    415
    Jacek Dziedzic
    Sep 21, 2006
  4. RS
    Replies:
    0
    Views:
    355
  5. antsor
    Replies:
    0
    Views:
    869
    antsor
    Feb 12, 2012
Loading...

Share This Page