1

new to C here. I am making a program that will sort and search a list of random ints for learning purposes, and trying to implement Bubble sort, but am getting odd results in my console during debugging.

I have an array like so:

arr[0] = 3
arr[1] = 2
arr[2] = 1

So if I was to sort this list from least to greatest, it should be in the reverse order. Instead, my sort function seems to be logically flawed, and is outputting the following.

arr[0] = 0
arr[1] = 1
arr[2] = 2

Obviously I am new because someone that knows better will probably spot my mistake very quickly.

find.c

/**
 * Prompts user for as many as MAX values until EOF is reached, 
 * then proceeds to search that "haystack" of values for given needle.
 *
 * Usage: ./find needle
 *
 * where needle is the value to find in a haystack of values
 */

#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>

#include "helpers.h"

// maximum amount of hay
const int MAX = 65536;

int main(int argc, string argv[])
{
    // ensure proper usage
    if (argc != 2)
    {
        printf("Usage: ./find needle\n");
        return -1;
    }

    // remember needle
    int needle = atoi(argv[1]);

    // fill haystack
    int size;
    int haystack[MAX];
    for (size = 0; size < MAX; size++)
    {
        // wait for hay until EOF
        printf("\nhaystack[%i] = ", size);
        int straw = get_int();
        if (straw == INT_MAX)
        {
            break;
        }

        // add hay to stack
        haystack[size] = straw;
    }
    printf("\n");

    // sort the haystack
    sort(haystack, size);

    // try to find needle in haystack
    if (search(needle, haystack, size))
    {
        printf("\nFound needle in haystack!\n\n");
        return 0;
    }
    else
    {
        printf("\nDidn't find needle in haystack.\n\n");
        return 1;
    }
}

helpers.c

#include <cs50.h>

#include "helpers.h"
#include <stdio.h>
/**
 * Returns true if value is in array of n values, else false.
 */
bool search(int value, int values[], int n)
{
    // TODO: implement a searching algorithm
    return false;
}

/**
 * Sorts array of n values.
 */
void sort(int values[], int n)
{
    // TODO: implement an O(n^2) sorting algorithm
    int tmp = 0;
    int i = 0;
    bool swapped = false;
    bool sorted = false;

    for (int i = 0; i < n; i++)
    {
        printf("%i\n", values[i]);
    }

    while (!sorted)
    {
        //check if number on left is greater than number on right in sequential order of the array.
        if (values[i] > values[i+1])
        {
            tmp = values[i];
            values[i] = values[i+1];
            values[i+1] = tmp;
            swapped = true;
        }
        if (i >= n - 1)
        {
            if (!swapped)
            {
                //No swaps occured, meaning I can assume the list is sorted.
                for (int i = 0; i < n; i++)
                {
                    printf("%i\n", values[i]);
                }
                sorted = true;
                break;
            } else {
                //A swap occured on this pass through of the array.  Set the flag back to false for the next pass through, repeating until no swaps are detected.  (Meaning every number is in its proper place.)
                i = 0;
                swapped = false;
            }
        } else {
            i++;
        }
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
JohnWick
  • 4,929
  • 9
  • 37
  • 74
  • 1
    Do you really need to provide your own implementation of `sort`? C has one [in the standard library](http://stackoverflow.com/questions/1787996/c-library-function-to-do-sort) – Code Different Mar 25 '17 at 15:09
  • Step through the program in your debugger, and examine the values of variables as you go. – Barmar Mar 25 '17 at 15:10
  • 1
    @CodeDifferent He's obviously trying to learn algorithms. – Barmar Mar 25 '17 at 15:10
  • @Barmar Hi, I've done this but getting a bit confused on how I am ending up with the 0. :( Obviously my output is actually pretty close to what it should be, just seems to be 1 number off somewhere. I've tweaked some of the conditionals and still seems to end up with this problem. – JohnWick Mar 25 '17 at 15:12
  • @CodeDifferent I appreciate the response, but this is purely for educational purposes. – JohnWick Mar 25 '17 at 15:12
  • There's no need for the `sorted` variable. When you set it to true, you also use `break`, so that ends the loop. You can just use `while (true)`. – Barmar Mar 25 '17 at 15:20
  • @Barmar Hey yeah I actually had it as that earlier, for some reason I put that flag back and not sure why. Don't think it affects my problem much though right? Atleast in this case... – JohnWick Mar 25 '17 at 15:21
  • No, it's not related to the problem. – Barmar Mar 25 '17 at 15:22
  • Ironic that the person with moniker _Code Different_ would be the only one that suggests using the _standard_ library. :) – ryyker Mar 25 '17 at 16:11

2 Answers2

3

The problem is that you do the comparison and swap before you do the test if (i >= n - 1). This means that it will compare values[i] > values[i+1] when i == n-1, so it will access outside the array bounds, which is undefined behavior. In your case, there happens to be 0 in the memory after the array, so this is getting swapped into the array, and then it gets sorted to the beginning of the array.

Change

    if (values[i] > values[i+1])

to

    if (i < n-1 && values[i] > values[i+1])
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • @PaulOgilvie I've changed my answer, please take a look. – Barmar Mar 25 '17 at 15:39
  • @Barmar I swear I thought I had tried adding the AND condition to the first check, and got the same result, but just tried it again and I am getting proper outputs. I'm going to go ahead and mark this as the answer. Thank you! – JohnWick Mar 25 '17 at 15:45
  • Good catch, Barmar! (Would be nicer to move the cmp/swap to the else part.) – Paul Ogilvie Mar 25 '17 at 17:59
  • 1
    @PaulOgilvie There's probably better ways to refactor it, but I felt like keeping my changes to a minimum. – Barmar Mar 27 '17 at 14:44
  • 1
    Yea, thought so. It was maybe more a note to the OP than to you. This way you make the point more clear. – Paul Ogilvie Mar 27 '17 at 15:06
  • @Paul Ogilvie I appreciate the help guys, I would refactor it if I was going to be using the code in production (in which case I would likely just use the library function lol)...probably still good for learning purposes but oh well :P – JohnWick Mar 28 '17 at 01:04
  • @DavidStampher I think Paul's point is that when you're learning algorithms, you should try to implement them in a logical way. While it's sometimes hard to avoid, repeated tests of the same thing is often the sign of an illogical design. – Barmar Mar 28 '17 at 01:17
  • @Barmar Well, still a long way to go. I'd say getting as far missing just 1 last AND condition isn't so bad :P And I had actually tried this solution myself before posting here, I literally must have just accidentally not compiled before testing it. :( – JohnWick Mar 28 '17 at 01:21
  • I am a bit confused on the repeated tests of the same thing part though, it seems to me I am comparing different variables in my loop each iteration, since I am incrementing my index for values[]? Please elaborate in my specific case. With that said I removed the sorted bool, because like you said it was totally unnecessary. – JohnWick Mar 28 '17 at 01:25
  • It's checking for the last element of the array in two places, the change I made in my answer, and the original code's `if (i >= n - 1)`. – Barmar Mar 28 '17 at 15:38
2

The highest entries you can swap in an array 0..n-1 are n-2 and n-1. So i may not be larger than n-2 so i+1 accesses n-1.

Therefore your check must be:

if (i > n - 2)
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • The block of code inside `if (i > n -1)` never does any swaps, so this isn't a problem. It either breaks out of the loop or sets `i = 0`. – Barmar Mar 25 '17 at 15:19
  • Yeah just tried this solution, seemed legit. Got the same output though. Blah. @Paul Ogilvie – JohnWick Mar 25 '17 at 15:20
  • @Barmar, the problem is the `else i++;` which would now address out of bounds. – Paul Ogilvie Mar 25 '17 at 15:22
  • 1
    David, print the array after input and before sort; then sort and then print again. I can't see anything else wrong with sort. – Paul Ogilvie Mar 25 '17 at 15:27
  • @PaulOgilvie Will do that, but I just wanted to mention I made the check i > n - 3 and it outputted the correct result. I am really confused as to why, but that must be the issue. – JohnWick Mar 25 '17 at 15:36
  • That seems unlikely. Is there also a bug in reading the input? See my edit. – Paul Ogilvie Mar 25 '17 at 17:08
  • I undid my edit as it was incorrect. But `i > n-3` seems wrong. – Paul Ogilvie Mar 25 '17 at 17:10
  • @PaulOgilvie Yeah it wasn't that, although it did work. Adding the && i < n - 1 check to my original conditional fixed the problem entirely. Sad part is I thought I had tried that :( Perhaps I forgot to compile... – JohnWick Mar 25 '17 at 17:30