动态分配堆栈和指针算法的奇数内存错误

时间:2016-06-16 17:48:27

标签: c memory-management valgrind heap-memory pointer-arithmetic

我正在尝试使用动态内存和指针算法构建一个堆栈来遍历堆栈。我收到的错误似乎无法解决。错误因我运行程序的方式而异。 1)如果我只使用args运行,我会在第112行的fClose之前得到一个segFault,并且没有pFile不是NULL。 2)如果我运行少于20个项目被送入堆栈一切正常,只有当我第二次重新分配堆栈时才开始出错 3)如果我使用超过20个元素和valgrind运行它,它会一直运行但有一些读/写错误,主要是在pushStack中。

我一直在想我越来越近了,但此时我更迷失了。我相信这可能不是一个堆栈的最佳实现,但我仍然无法弄清楚为什么它不会工作一段时间。

源代码:

    /**********************************************************************
CS2123 assignment2_stacks.c by Kyle Widmann
Purpose:
    This program takes a file supplied by user and reads each line, which is expected to be an int.  A stack is implemented using dynamic memory.  If the int is -99999 the stack is popped.  Otherwise the number is pushed onto the stack.  The stack increased by chunks of 10, but never decreases.
Command Parameters:
    assignment2 -i datafile.txt
Input:
    numbers supplied by datafile.txt from Command Line

    -The file is assumed to be nothing but integers.
    -All integers >-99999 will be pushed onto stack
    -Reading -99999 will cause the stack to pop
Results:
    Whenever the stack is popped the program prints elements remaning after the pop, and what integer was popped.  The program also prints whenver the stack size grows, as well as what the old and new stack sizes are.
Returns:
    0 - normal
Notes:

**********************************************************************/

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

//Typedef for our stack
typedef struct stack{
    int iInfo;
    int iCount;
    int iStackSize;
}STACK;

//Define our definitions for True, False and Pop
#define TRUE 0
#define FALSE -1
#define POP -99999

//Declaration of functions
STACK *makeStack();
STACK *increaseStack(STACK *pStack);
int stackPush(int x, STACK **ppStack);
int stackPop(STACK **ppStack);
int stackEmpty(STACK *pStack);
int stackFull(STACK *pStack);
void getFile(int argc, char *argv[], char **ppszInputFile);
void readFile();

/**************************** MAIN FUNCTION ************************/
int main(int argc, char *argv[])
{
    printf("Assignment 2 written by Kyle Widmann\n\n");

    //Pointer to input file from CLI, and stack to be used across program
    char *pszInputFile = NULL;
    STACK *pStack = makeStack();

    //Get the filename from the CLI
    getFile(argc, argv, &pszInputFile);

    //Open and read the file, pushing/popping as necessary
    readFile(pszInputFile, &pStack);

    //reset pStack to beginning of stack and free

    //GETTING ERRORS HERE????

    // printf("about to initialize iCount\n");
    int iCount = (int)pStack->iCount;
    // printf(" in Main. iCount: %d\n", iCount);
    pStack = pStack-(iCount-1);
    // printf("in Main. pStack: %p\n", pStack);
    free(pStack);

    return 0;
}

void readFile(char *pszInputFile, STACK **ppStack){
    char szInputBuffer[100];    //Input buffer to read from file
    int iInput;                 //variable to store the int read from file
    int iPop=0;                 //variable to store the popped int
    FILE *pFile;                //pointer to input file

    //Open the file
    pFile = fopen(pszInputFile, "r");
    if(pFile == NULL)
        printf("Error opening file;");

    printf("pFile addres: %p\n", pFile);

    while(fgets(szInputBuffer, 100, pFile) != NULL){
        if(sscanf(szInputBuffer, "%d[^\n]", &iInput) == 1){
            // printf("input: %d... \t", iInput);
            if(iInput == POP){
                // printf("about to Pop\n");
                iPop = stackPop(ppStack);
                if(iPop == FALSE){
                    printf("There was an error popping the stack\n");
                }
                else{
                    printf("Number of elements after popping: %d \t\t Integer popped: %d\n", (*ppStack)->iCount, iPop);
                }
            }
            else{
                printf("About to push %d \tStackSize: %d\tStackCount: %d\n", iInput, (*ppStack)->iStackSize, (*ppStack)->iCount);
                stackPush(iInput, ppStack);
            }
        }
    }

    // GETTING ERRORS HERE???

    // printf("pFile addres: %p\n", pFile);
    if(pFile != NULL){
        fclose(pFile);
        pFile = NULL;
    }
}

STACK *makeStack(){
    STACK *stack = (STACK *)malloc(sizeof(STACK)*10);
    stack->iInfo = 0;
    stack->iCount = 0;
    stack->iStackSize = 10;
    if(stack == NULL){
        printf("Error allocating stack\n");
    }
    return stack;
}

STACK *increaseStack(STACK *pStack){
    // printf("inside increase stack.  iCount: %d\tiStackSize: %d\n", pStack->iCount, pStack->iStackSize);

    //Set old stack size and old count of elements to redirect new stack after realloc
    int iOldCapacity = pStack->iStackSize;
    int iOldCount = (int)pStack->iCount;

    //set pStack back to the beggining of the HEAP
    pStack = pStack-(pStack->iCount-1);

    // printf("iCount after resetting to beginnign: %d\n", (pStack+iOldCount-1)->iCount);

    //Realloc pStack and add 10 spaces
    pStack = (STACK *)realloc(pStack, (sizeof(STACK)*(pStack->iStackSize + 10)));

    // printf("Printing Stack...\n");
    // int i;
    // for(i = 0; i<iOldCount; i++){
    //     printf("Address: %p\tiCount: %d\t, iStackSize: %d\n", pStack+i, (pStack+i)->iCount, (pStack+i)->iStackSize);
    // }

    //point pStack back to the last element pushed onto stack
    pStack = pStack + (iOldCount-1);

    //Update the size of stack
    pStack->iStackSize = pStack->iStackSize +10;

    // printf("Post realloc.  iCount: %d\tiStackSize: %d\n", pStack->iCount, pStack->iStackSize);

    //Print out that the stack has grown.
    printf("Stack capacity has grown from %d to %d\n", iOldCapacity, pStack->iStackSize);
    return pStack;
}

int stackPush(int x, STACK **ppStack){
    if(stackFull(*ppStack) == TRUE){
        //increase stack size
        *ppStack = increaseStack(*ppStack);
    }

    //set first element
    if(stackEmpty(*ppStack) == TRUE){
        (*ppStack)->iInfo = x;
        (*ppStack)->iCount = (*ppStack)->iCount + 1;
    }
    else
    {
        //Set the next element in stack
        (*ppStack+1)->iInfo = x;
        (*ppStack+1)->iCount = (*ppStack)->iCount +1;
        (*ppStack+1)->iStackSize = (*ppStack)->iStackSize;
        //ensure always pointing to top
        *ppStack = (*ppStack + 1);
    }

    return TRUE;
}

int stackPop(STACK **ppStack){
    int iPop;

    // if the stack is not empty
    if(stackEmpty(*ppStack) == FALSE){
        iPop = (*ppStack)->iInfo;
        (*ppStack-1)->iStackSize = (*ppStack)->iStackSize;

        //set the stack pointing to the previous element since current element was popped
        *ppStack = (*ppStack -1);
        return iPop;
    }

    return FALSE;
}

int stackEmpty(STACK *pStack){
    if(pStack->iCount > 0){
        return FALSE;
    }
    return TRUE;
}

int stackFull(STACK *pStack){
    if(pStack->iCount + 1 == pStack->iStackSize){
        return TRUE;
    }
    return FALSE;
}

/********************************* getFile ******************************
void getFile(int argc, char *argv[], char **ppszInputFile)
Purpose:
    Reads the CLI to assign file name containing student info to pszInputFile
Parameters:
    I   int argc                    the count of command line arguments
    I   char argv[]                 Array of the command line arguments
    I/O char **ppszInputFile        Double pointer to character string for the file name
Notes:
**************************************************************************/

void getFile(int argc, char *argv[], char **ppszInputFile)
{
    int i;

    for (i = 1; i < argc; i++)
    {
        // check for a switch
        if (argv[i][0] != '-')
            printf("Error: Switch expected");
        // determine which switch it is
        switch (argv[i][1])
        {
        case 'i':                   // Book File Name
            if (++i >= argc)
                printf("Error: Missing Switch\n");
            // check for too long of a file anme
            else
                *ppszInputFile = argv[i];
            break;
        default:
            printf("Error: Switch expected");
        }
    }
}

Valgrind输出:

valgrind --leak-check=full --show-leak-kinds=all ./stacks -i data_a2.txt
==7116== Memcheck, a memory error detector
==7116== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7116== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==7116== Command: ./stacks -i data_a2.txt
==7116== 
Assignment 2 written by Kyle Widmann

Size of STACK: 12   Size of stack: 12 Size of STACK*10: 120
pFile addres: 0x5203540
About to push 29    StackSize: 10   StackCount: 0
About to push 5     StackSize: 10   StackCount: 1
About to push 7295  StackSize: 10   StackCount: 2
About to push 103   StackSize: 10   StackCount: 3
About to push 394   StackSize: 10   StackCount: 4
Number of elements after popping: 4          Integer popped: 394
Number of elements after popping: 3          Integer popped: 103
About to push 48    StackSize: 10   StackCount: 3
About to push 12    StackSize: 10   StackCount: 4
About to push 839   StackSize: 10   StackCount: 5
About to push 55    StackSize: 10   StackCount: 6
Number of elements after popping: 6          Integer popped: 55
About to push 28    StackSize: 10   StackCount: 6
About to push 91    StackSize: 10   StackCount: 7
About to push 523   StackSize: 10   StackCount: 8
Number of elements after popping: 8          Integer popped: 523
About to push 289   StackSize: 10   StackCount: 8
About to push 32    StackSize: 10   StackCount: 9
inside increase stack.  iCount: 9   iStackSize: 10
iCount after resetting to beginnign: 9
Printing Stack...
Address: 0x52047f0  iCount: 1   , iStackSize: 10
Address: 0x52047fc  iCount: 2   , iStackSize: 10
Address: 0x5204808  iCount: 3   , iStackSize: 10
Address: 0x5204814  iCount: 4   , iStackSize: 10
Address: 0x5204820  iCount: 5   , iStackSize: 10
Address: 0x520482c  iCount: 6   , iStackSize: 10
Address: 0x5204838  iCount: 7   , iStackSize: 10
Address: 0x5204844  iCount: 8   , iStackSize: 10
Address: 0x5204850  iCount: 9   , iStackSize: 10
Post realloc.  iCount: 9    iStackSize: 20
Stack capacity has grown from 10 to 20
About to push 414   StackSize: 20   StackCount: 10
Number of elements after popping: 10         Integer popped: 414
About to push 829   StackSize: 20   StackCount: 10
About to push 21    StackSize: 20   StackCount: 11
About to push 9     StackSize: 20   StackCount: 12
About to push 45    StackSize: 20   StackCount: 13
About to push 299   StackSize: 20   StackCount: 14
About to push 101   StackSize: 20   StackCount: 15
Number of elements after popping: 15         Integer popped: 101
About to push 3     StackSize: 20   StackCount: 15
About to push 88    StackSize: 20   StackCount: 16
About to push 718   StackSize: 20   StackCount: 17
About to push 501   StackSize: 20   StackCount: 18
Number of elements after popping: 18         Integer popped: 501
About to push 39    StackSize: 20   StackCount: 18
About to push 89    StackSize: 20   StackCount: 19
inside increase stack.  iCount: 19  iStackSize: 20
iCount after resetting to beginnign: 19
Printing Stack...
Address: 0x5204920  iCount: 1   , iStackSize: 10
Address: 0x520492c  iCount: 2   , iStackSize: 10
Address: 0x5204938  iCount: 3   , iStackSize: 10
Address: 0x5204944  iCount: 4   , iStackSize: 10
Address: 0x5204950  iCount: 5   , iStackSize: 10
Address: 0x520495c  iCount: 6   , iStackSize: 10
Address: 0x5204968  iCount: 7   , iStackSize: 10
Address: 0x5204974  iCount: 8   , iStackSize: 10
Address: 0x5204980  iCount: 9   , iStackSize: 20
Address: 0x520498c  iCount: 10  , iStackSize: 20
Address: 0x5204998  iCount: 11  , iStackSize: 20
Address: 0x52049a4  iCount: 12  , iStackSize: 20
Address: 0x52049b0  iCount: 13  , iStackSize: 20
Address: 0x52049bc  iCount: 14  , iStackSize: 20
Address: 0x52049c8  iCount: 15  , iStackSize: 20
Address: 0x52049d4  iCount: 16  , iStackSize: 20
Address: 0x52049e0  iCount: 17  , iStackSize: 20
Address: 0x52049ec  iCount: 18  , iStackSize: 20
Address: 0x52049f8  iCount: 19  , iStackSize: 20
Post realloc.  iCount: 19   iStackSize: 30
Stack capacity has grown from 20 to 30
About to push 47    StackSize: 30   StackCount: 20
==7116== Invalid write of size 4
==7116==    at 0x400D30: stackPush (assignment2_stacks.c:162)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116==  Address 0x5204a10 is 0 bytes after a block of size 240 alloc'd
==7116==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7116==    by 0x400BAE: increaseStack (assignment2_stacks.c:133)
==7116==    by 0x400CDF: stackPush (assignment2_stacks.c:153)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116== 
==7116== Invalid write of size 4
==7116==    at 0x400D4A: stackPush (assignment2_stacks.c:163)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116==  Address 0x5204a14 is 4 bytes after a block of size 240 alloc'd
==7116==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7116==    by 0x400BAE: increaseStack (assignment2_stacks.c:133)
==7116==    by 0x400CDF: stackPush (assignment2_stacks.c:153)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116== 
==7116== Invalid write of size 4
==7116==    at 0x400D62: stackPush (assignment2_stacks.c:164)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116==  Address 0x5204a18 is 8 bytes after a block of size 240 alloc'd
==7116==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7116==    by 0x400BAE: increaseStack (assignment2_stacks.c:133)
==7116==    by 0x400CDF: stackPush (assignment2_stacks.c:153)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116== 
pFile addres: 0x5203540
about to initialize iCount
==7116== Invalid read of size 4
==7116==    at 0x40086F: main (assignment2_stacks.c:64)
==7116==  Address 0x5204a14 is 4 bytes after a block of size 240 alloc'd
==7116==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7116==    by 0x400BAE: increaseStack (assignment2_stacks.c:133)
==7116==    by 0x400CDF: stackPush (assignment2_stacks.c:153)
==7116==    by 0x400A1B: readFile (assignment2_stacks.c:101)
==7116==    by 0x400860: main (assignment2_stacks.c:60)
==7116== 
 in Main. iCount: 21
in Main. pStack: 0x5204920
==7116== 
==7116== HEAP SUMMARY:
==7116==     in use at exit: 0 bytes in 0 blocks
==7116==   total heap usage: 6 allocs, 6 frees, 6,272 bytes allocated
==7116== 
==7116== All heap blocks were freed -- no leaks are possible
==7116== 
==7116== For counts of detected and suppressed errors, rerun with: -v
==7116== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)

1 个答案:

答案 0 :(得分:1)

问题出在你的increaseStack()函数中,它与我在评论中观察到你保留了大量冗余数据有关。请特别注意在第二次堆栈扩展后立即出现问题 - 这不是巧合。

以下是increaseStack()功能行为的高级描述:

  1. 记录堆栈容量和元素数量,如提供的元素指针所示。

  2. 使用记录的元素计数将元素指针调整为指向最底部的堆栈元素。

  3. 重新分配,根据当前元素指针指示的容量选择新容量(现在指向最底部的元素)。

  4. 调整堆栈指针以指向与其在函数入口上指向的元素对应的重新分配空间的元素。

  5. 更新堆栈指针所指向的元素中记录的堆栈容量。

  6. 仔细研究步骤3和5,并考虑为什么你的方法适用于第一次堆栈扩展,而不是第二次。

    我怀疑我知道你的解决方案的第一个倾向是什么,但抵制它。相反,请考虑一下如何更好地设计它。特别是,对每个元素单独iCountiStackSize会有什么好处? (提示:没有。)

    我建议您改变struct stack

    typedef struct stack{
        int *iInfo;
        int iCount;
        int iStackSize;
    }STACK;
    

    然后,只维护一个struct stack,并在其iInfo成员上执行动态分配/重新分配。使用基于iCount的简单索引语法来存储值,并从iInfo指向的空间中检索它们。