Dennis Haarbrink
Dennis Haarbrink

Reputation: 3760

Program misbehaves 25% of the time

Inspired by this topic, I decided to write a simple program that does exactly that.
The logic isn't complicated and I have a working program 75% of the time.. The amount of asked numbers is defined as #define BUFSIZE x, where x can be an arbitrary int.
The problem arises when ((BUFSIZE+1) % sizeof(int)) == 0.

So for example, if BUFSIZE=10, my program behaves correctly, when BUFSIZE=11 I get odd behaviour.

Here is the sourcecode:

#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 7

int max(int *buf);

int main()
{
    int bufsize = BUFSIZE, *buf = malloc(sizeof(int[bufsize]));

    // read values
    int *ptr = buf;
    while(--bufsize + 1)
    {
        printf("Input %d: ", BUFSIZE - bufsize);
        scanf("%d", ptr);
        ++ptr;
    }

    // reset pointer and determine max
    ptr = buf;
    printf("\nMax: %d\n", max(ptr));
    // cleanup
    free(buf);
    ptr = NULL;
    buf = NULL;

    exit(EXIT_SUCCESS);
}

int max(int *buf)
{
    int max = 0;
    while(*buf)
    {
        printf("%d\n", *buf);
        if(*buf > max) max = *buf;
        ++buf;
    }
    return max;
}

And some sample output for BUFSIZE=2 (correct) and BUFSIZE=3 (incorrect).

suze:/home/born05/htdocs/experiments/c# gcc input.c && ./a.out
Input 1: 12
Input 2: 23
12
23

Max: 23

suze:/home/born05/htdocs/experiments/c# gcc input.c && ./a.out
Input 1: 12
Input 2: 23
Input 3: 34
12
23
34
135153

Max: 135153

I have the feeling it is something extremely logical but I can't put my finger on the exact cause of this misbehaviour. Could someone point out the (perhaps obvious) flaw to me?

Upvotes: 1

Views: 222

Answers (3)

Amardeep AC9MF
Amardeep AC9MF

Reputation: 19054

You're treating buf as if it was a null terminated string array. You could do that if your data values are guaranteed never to be zero and you actually put the zero there (which your program isn't doing).

Rather try changing your max() function to something like this (adjusting prototype and calling location accordingly):

int max(int *buf, int count)
{
    int max = 0;

    // Check inputs
    if (buf == NULL || count <= 0)
    {
        printf("max(): bad parameter(s)\n");
        return 0;
    }

    while(count--)
    {
        printf("%d\n", *buf);
        if(*buf > max) max = *buf;
        ++buf;
    }
    return max;
}

Upvotes: 1

Tyler McHenry
Tyler McHenry

Reputation: 76730

It's actually pure luck that this even works for any values of BUFSIZE. (In fact, for me, it breaks on BUFSIZE=2). Here's why -- this:

while(*buf)

Is not an appropriate way to check for the end of your buffer. What this does is load the value at the address pointed to by buf and see if the contents are zero. Since you're never explicitly putting a zero at the end of your buffer, that's never necessarily going to be true, and that loop could run potentially forever, reading into memory that is past the end of your buf array and invoking undefined behavior.

You either need to allocate an extra element at the end of the buf array and set it to zero (but then your program won't work right if the user enters 0 as input), or explicitly pass the size of buf to the max function and use that to determine when you should stop looping.

Upvotes: 5

sharptooth
sharptooth

Reputation: 170509

This

int bufsize = BUFSIZE, *buf = malloc(sizeof(int[bufsize]));

should be

int bufsize = BUFSIZE, *buf = malloc(sizeof(int[BUFSIZE + 1]));
buf[BUFSIZE] = 0;

In your current code you allocate memory for one integer (sizeof(int[bufsize]) evaluates to sizeof(int*)), instead you need memory for BUFSIZE integers and one extra integer containing null afterwards.

In your current code you have so-called undefined behavior - you use memory not legally allocated to you. In your case it sometimes works sometimes not. Well, at least you know it right now, not when it is pushes to control a nuclear power plant.

Upvotes: 2

Related Questions