如何调试树求和和运行时错误?

时间:2016-03-13 09:26:10

标签: c algorithm

我正在从UVa Online Judge看problem 112

几个星期前,我从我的大学得到了一些作业,问题是,虽然UVa上接受了其他问题,但我无法弄清楚这个问题出了什么问题。我已经运行Udebug website的输入,没有问题。我仔细检查了结果,现在,我已经厌倦了解决这个问题。

以下是有关已发生事件的详细信息。首先,我将BUFSIZE增加到2 ^ 20以避免任何内存溢出。结果?失败。其次,我缩小了我制作的堆栈中元素的大小。结果?失败。最后,为了以防万一,我删除了结果的eol字符。结果?失败。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define BUFSIZE 16384

typedef struct node {
    int element[BUFSIZE];
    int size;
    int current;
}Stack;//This is a stack I made

static Stack *stack;
static int level;//This is a level of a node in the whole tree
static int integer;//This is an integer that should be came out from the sum() function

bool initialize(void) {
    if (stack == NULL)
        stack = (Stack *)malloc(sizeof(Stack));

    stack->size = BUFSIZE;
    stack->current = 0;
    return true;
}

bool push(int number) {
    if (stack == NULL)
        return false;
    if ((stack->current + 1) > stack->size)
        return false;

    stack->element[stack->current] = number;
    stack->current++;
    return true;
}

int pop() {
    if (stack->current <= 0)
        return 0xFFFFFFFF;
    stack->current--;
    return stack->element[stack->current];
}

int sum() {
    int result = 0;
    int i;
    if (stack == NULL)
        return 0xFFFFFFFF;
    if (stack->current == 0)
        return 0xFFFFFFFF;

    for (i = 0; i < stack->current; i++)
        result += stack->element[i];

    return result;
}//Sum all the values in the stack and return it.

void replace(char * o_string, char * s_string, char * r_string) {
    char *buffer = (char *)calloc(BUFSIZE, sizeof(char));
    char * ch;

    if (!(ch = strstr(o_string, s_string)))
        return;
    strncpy(buffer, o_string, ch - o_string);
    buffer[ch - o_string] = 0;
    sprintf(buffer + (ch - o_string), "%s%s", r_string, ch + strlen(s_string));
    o_string[0] = 0;
    strcpy(o_string, buffer);
    free(buffer);
    return replace(o_string, s_string, r_string);
}//This is a function I found on Google. Memory usage optimization is not guaranteed.


int main(void) {
    char *buffer;
    char *line;
    char *restOfTheString;
    char *token;
    bool checked = false, found = false;

    int i = 0, j = 0, scannedInteger, result = 0, array[4096];

    buffer = (char *)calloc(BUFSIZE, sizeof(char));
    restOfTheString = (char *)calloc(BUFSIZE, sizeof(char));
    line = (char *)calloc(BUFSIZE, sizeof(char));
    memset(buffer, 0, BUFSIZE);
    for (i = 0; i < 4096; i++) {
        array[i] = -1;
    }
    level = 0;
    integer = 0;

    while (fgets(line, sizeof(line), stdin) != NULL) {//Get input line by line
        if (line[0] != '\n') {
            token = strtok(line, "\n");
            if (strlen(line) >= 1) {
                strcat(buffer, token);
            }
        }   
    }

    replace(buffer, " ", "");
    replace(buffer, "()()", "K");

    strcpy(restOfTheString, buffer);
    i = 0;
    while (restOfTheString[i] != 0) {
        if (level == 0 && !checked) {//If the level of the node is 0, then it is clearly the summed value I need to find out on the whole tree.
            initialize();
            sscanf(&restOfTheString[i], "%d%s", &integer, &restOfTheString[0]);
            i = -1;
            checked = true;
        }

        if (restOfTheString[i] == '(') {
            checked = false;
            level++;
        }//If there is an openning bracket, then increase the level of the node.
        else if (restOfTheString[i] == ')') {
            if (restOfTheString[i - 1] != '(')
                if (pop() == 0xFFFFFFFF)
                    return 0;
            level--;
            if (!found && level == 0) {
                array[j] = 0;
                j++;
                free(stack);
                stack = NULL;
            }//If there is a closing bracket, then it's time to check whether the level of the node is 0. If the level of the node is 0, then we need to report the result to the 'array' which is an integer array and move on to the next input.
            else if (found && level == 0) {
                array[j] = 1;
                j++;
                free(stack);
                stack = NULL;
                found = false;
            }
        }
        else if (restOfTheString[i] == '-' && !checked) {
            if (sscanf(&restOfTheString[i], "%d%s", &scannedInteger, &restOfTheString[0]) == 2) {
                if (push(scannedInteger) == false)
                    return 0;
                i = -1;
            }
        }//If there is a minus character, then it's obvious that the next couple of characters are a negative integer and I need to scan it out of the whole input.
        else if (restOfTheString[i] >= 48 && restOfTheString[i] <= 57 && !checked) {
            if (sscanf(&restOfTheString[i], "%d%s", &scannedInteger, &restOfTheString[0]) == 2) {
                if (push(scannedInteger) == false)
                    return 0;
                i = -1;
            }
        }//If there is a numerous character, then it's obvious that the next couple of characters are a negative integer and I need to scan it out of the whole input.

        else if (restOfTheString[i] == 'K') {
            if ((result = sum()) == 0xFFFFFFFF)
                return 0;
            if (result == integer) {
                found = true;
            }
        }//The 'K' character means the integer scanned prior to this iteration is a value in a leaf. So I need to call the sum() function in order to figure it out the result.
        i++;
    }
    i = 0;
    while (array[i] != -1) {
        if (array[i] == 1)
            printf("yes\n");
        else if (array[i] == 0)
            printf("no\n");
        i++;
    }
    return 0;
}

虽然显然对内存使用情况持怀疑态度,但我不知道如何在我的系统上跟踪堆栈。

1 个答案:

答案 0 :(得分:0)

你使用了许多有问题的做法。

  • 您可以从头开始释放并重新分配堆栈。在您的情况下,堆栈具有固定的大小;在主要开始时分配一个,在结尾时分配一次。

  • 您将索引i设置为-1作为指标,但稍后继续访问restOfString[i]restOfString是一个已分配的字符串,在实际数据写入之前写入字节可能会破坏系统为分配的内存保留的内部信息。这可能会在释放时导致错误。在任何情况下,它都是未定义的行为。

  • 您按行读取输入并将所有内容连接成一个巨大的字符串。您可以使用strcat,这会随着字符串的增长而变慢。如果必须将所有内容加载到大缓冲区中,请考虑使用fread

  • 您的递归replace方法也会对临时分配的缓冲区进行大量复制。

  • 此:

    sscanf(&rest[i], "%d%s", &integer, &rest[0]);
    
    看起来很可疑。您将结果存储在您正在读取的字符串中,尽管是在不同的索引处。结果和源可能重叠,这可能是未定义的行为。无论如何,它需要大量的复制。您可以使用sscanf读取整数,而不是使用strtol,它会在解析数字后为您提供字符串的位置。继续在结果偏移处扫描旧字符串。

您的问题似乎不在核心算法中,而是读取输入。 Ihe assignment未提及最大行长度。这可能表示您不应该在行上下文中读取输入。

您可以使用不了解换行符的scanf函数。您可以利用数据转换不成功扫描的事实,例如:扫描整数,重置输入流。

这种策略只需要存储当前令牌。如果使用递归,则甚至不需要堆栈。我怀疑在线判断中的测试用例是否会破坏堆栈限制,即使它们包含具有较大深度的退化树。