1

Could you please help me debug a linear search program I wrote in C?

The do while loop seems to be executed only once without looping and, as a result, the program does not print the largest int as I intend it to do. When I replace all the variable As with an actual number like 7, the program works well. Would somebody please explain why this happens to me? (I am sorry that the entire program is clumsy. I apprecite your help in advance.)

#include <stdio.h>

int A;
void linear(int numbers[A]);

int main(void)
{
    int numbers[7] = {6, 0, 4, 1, 2, 3, 5};
    linear(numbers);
}

void linear(int numbers[A])
{
    int n = 0;
    int i = 1;
    do
    {
        if (numbers[n] > numbers[n + i])
            i++;
        else
            n = n + i;
    }
    while (n + i < A);

    printf("%i\n", numbers[n]);
}

1 Answer 1

3

Actually, as written, it does print the largest number, but only from sheer coincidence. The largest number in the array is 6, which is also the first number. Since the loop only runs once, it's already there.

However, let's talk about what you're likely really trying to do, and think about the best ways to do so.

Based on what you say, "to print out the largest number", a linear search need only find the largest number. It also doesn't need to find the position of that number in the array. So, let's figure out how to do that.

But first, let's cure a couple bad habits now. This program uses a global variable, which is ordinarily a very bad practice. A global variable is a variable that is declared outside of main or any function. In this case, A is a global variable. A global can be a very useful tool, but only when it makes sense to do so (as you'll learn later.)

Why is it a bad habit? It can lead to errors when the variable is reused or "shadowed" somewhere in the program where it shouldn't be. Global variable shadowing occurs when a global variable name is declared somewhere else in the code as a local variable. The local variable will be a completely separate variable and will mask or hide the global variable. This should be avoided at all costs. For example, suppose counter were declared as a global variable. Later, it's assigned a value of 12 in main. Then, it's redeclared in a function, where it is assigned a value of 15. When the function returns to main, the value of 12 remains in the global variable, and the local variable in the function is destroyed when processing exits the function.

Or, suppose in the same scenario, the programmer was depending on getting the global variable's value of 12, but accidently declared it in the function without assigning a value. It would initialize to 0 by default. You can see the problem.

So, never use a global variable if you don't absolutely have to!

Next, variable names should almost always be descriptive!

It's a bad practice to use single letter variable names! They should be descriptive of what they do, such as array_size instead of A. One of the very few exceptions is for use as a counter in a for loop. Even then, the loop should be fairly short (think a few dozen lines of code at most). When you have a large for or while loop, it's best to use descriptive names instead of single letters.

When using single letters in loops as counters, they should generally be i, j, k and so on, as it is traditional practice to use i for the outer loop and sequential letters for any nested loops inside that outer loop. Reusing i in subsequent outer loops is also standard practice. The important thing is to avoid confusion.

Now, on to the code to find the largest element in an array.

There are a lot of issues in the code above, too many to go through and be clear. So, since I don't believe this is actually an assignment, I decided to give you a clear example of how to accomplish it. Work through it yourself first to see if you understand. Pay special attention to what is being compared and how and where variables change.

#include <stdio.h>

void linear(int numbers[], int size);

int main(void)
{
    int numbers[7] = {0, 4, 1, 6, 2, 3, 5};

    // this is how you find the number of array elements
    // divide the array total size by the size of the first element. Google it.
    // note: you can't use this on a function parameter.
    // See https://www.geeksforgeeks.org/using-sizof-operator-with-array-paratmeters-in-c/

    int size = sizeof(numbers) / sizeof(numbers[0]) ;

    linear(numbers, size);
}

void linear(int numbers[], int size)
{
    int n = 0;       // holds index of current largest value, starting at the first array element.
    int i = 1;       // a counter, starting at the second element in the array.

    // find the index of the largest element
    do 
    {
        if (numbers[n] < numbers[i])
        {
            n = i;
        }
        i++;
    } while (i < size);

    printf("%i\n", numbers[n]);
}

Still, this code is problematic. What happens when there's only one element in the array? Will it fail? Will it produce a result? An error? Why don't you test that condition! ;-)

This would be better accomplished with a for loop than a while loop. (That's not to say there's not a better way to do it with a while loop.) Also, there are always multiple ways to do just about anything, but the most efficient (usually the simplest) is the best way.

The way to choose whether to use a for loop or a while or do/while loop is usually pretty straightforward.

If you have to do something until a certain test condition is met (such as A > B ) and you don't have a solid idea how many loop iterations it will take, then a while or do/while is probably the best choice.

If you have to do something a fixed number of times (meaning a fixed constant in the program or the number of times equal to the contents of a var ), then a for loop is usually the best choice. For example, if you have to look at every element in an array, for (int i = 0; i < array_count; i++) is the way to go. It consolidates the test and the counter incrementing into the for loop statement so you (or another programmer later) don't have to go searching for these control elements.

BTW, if you had only wanted to find the largest value, it would have been easier to just save the value in a var!

void linear(int numbers[], int size)
{
    int n = 0;       // holds index of current largest value, starting at the first array element.
    int i = 1;       // a counter, starting at the second element in the array.

    // find the largest element
    int largest = numbers[0];

    // Note that this for loop will make sure
    // that there's more than 1 element in the array.

    for (int i = 1; i < size && size > 1; i++)
    {
        if (largest < numbers[i])
        {
            largest = numbers[i];
        }
    }

    printf("%i\n", largest );    
}

This code uses a for loop and also makes sure it doesn't fail when an array only has 1 element.

One more coding tip - always try to do things the simplest way possible! It avoids a lot of mistakes. If something feels too complicated, it probably is. Try to simplify it, or to try and do less at the same time in each code section.

Now, if you intended to actually sort the list, that's an entirely different discussion.

Questions? ;-)

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

5
  • suggest that if you are going to pass the array without a size embedded in the braces, just pass a pointer, it looks very unstandard to pass int numbers[] as receiving argument along with size. i.e. void linear( int *numbers, int numbers_size) would be more standard.
    – UpAndAdam
    Commented Jan 23 at 16:16
  • 1
    There are three common ways to pass an array as a parameter to a function. When passing an array of unknown size, I prefer to use the brackets with nothing in them. This makes it very clear that the function is expecting an array and not a pointer to something that may or may not be an array. tutorialspoint.com/cprogramming/…
    – Cliff B
    Commented Jan 25 at 0:59
  • 1
    fair enough, but I've never encountered that in the past 20+ years I've been doing C/C++ so it seemed odd to me. Generally in C that's what the size parameter is passed for. but to each their own. I do think there is some nicety to that clearly being an array as opposed to potential a list passed with a list size. And would consider using that for my C specific coding in the future.
    – UpAndAdam
    Commented Jan 25 at 17:45
  • 1
    I think this is one of those best practice grey areas. Not saying either one is better, just my opinion and I respect yours too. There are some things we do because that's how it's always been done, or something that "old-school" does one way and "new-school" does another. (which is which here? ;-) )
    – Cliff B
    Commented Jan 26 at 3:48
  • Agree very grey however I just remembered the other reason I avoid doing this... confusion with Flexable Array Members, There is 'dark magic' in declarations of [] and [0] so I avoid [] and [0] generally as a result unless that's what I'm trying to do. Although you could say that usage in a function signature is different then a declaration of a variable; which is where it boils down to grey area of personal taste/style. For reference stackoverflow.com/questions/9722632/…
    – UpAndAdam
    Commented Jan 26 at 17:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .