Программа ведет себя плохо 25% времени - PullRequest
1 голос
/ 26 июля 2010

Вдохновленный этой темой , я решил написать простую программу, которая делает именно это.
Логика не сложная, и у меня есть рабочая программа 75% времени. Количество запрашиваемых чисел определяется как #define BUFSIZE x, где x может быть произвольным целым числом.
Проблема возникает, когда ((BUFSIZE+1) % sizeof(int)) == 0.

Так, например, если BUFSIZE=10, моя программа ведет себя правильно, когда BUFSIZE=11 я получаю странное поведение.

Вот исходный код:

#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;
}

И некоторые примеры вывода для BUFSIZE = 2 (правильно) и BUFSIZE = 3 (неправильно).

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

У меня такое чувство, что это что-то чрезвычайно логичное, но я не могу точно указать причину этого неправильного поведения. Может ли кто-нибудь указать на (возможно, очевидный) недостаток для меня?

Ответы [ 3 ]

5 голосов
/ 26 июля 2010

Это на самом деле просто удача, что это работает даже при любых значениях BUFSIZE. (На самом деле для меня это ломается на BUFSIZE=2). И вот почему - это:

while(*buf)

Не подходит для проверки конца вашего буфера. Для этого нужно загрузить значение по адресу, указанному buf, и посмотреть, равно ли его содержимое нулю. Поскольку вы никогда явно не ставите ноль в конце буфера, это не обязательно будет правдой, и этот цикл может выполняться потенциально вечно, читая в память, которая находится за концом вашего массива buf, и вызывая неопределенное поведение. .

Вам нужно либо выделить дополнительный элемент в конце массива buf и установить его на ноль (но тогда ваша программа не будет работать правильно, если пользователь введет 0 в качестве ввода), либо явно передать размер buf для функции max и используйте ее, чтобы определить, когда следует прекратить зацикливание.

2 голосов
/ 26 июля 2010

Это

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

должно быть

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

В вашем текущем коде вы выделяете память для одного целого числа (sizeof(int[bufsize]) оценивается в sizeof(int*)), вместо этого вам нужна память дляBUFSIZE целых чисел и одно дополнительное целое, содержащее нуль после.

В вашем текущем коде у вас есть так называемое неопределенное поведение - вы используете память, не выделенную вам по закону.В вашем случае это иногда работает, иногда нет.Ну, по крайней мере, вы знаете это прямо сейчас, а не тогда, когда это толкает к управлению атомной электростанцией.

1 голос
/ 26 июля 2010

Вы рассматриваете buf, как будто это массив строк с нулевым символом в конце.Вы можете сделать это, если ваши значения данных гарантированно никогда не будут равны нулю, и вы фактически поставите туда ноль (чего не делает ваша программа).

Скорее попробуйте изменить ваш max ()функционировать примерно так (корректируя прототип и вызывая местоположение соответственно):

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...