-2

So I have a stack of

struct board_struct {
    int rows; 
    int cols;
    char board[MAX_R][MAX_C]
};

typedef struct stack_S {
    Board boards[80];
    int size;
} Stack;

typedef struct board_struct Board;
typedef struct board_struct *BoardPtr;

I have

Board
*BoardPtr
Stack stack

When I push I want the current board to be put into the stack and then the program will change it and push the new board into the stack

lets say this pop function

Board pop() {

    stack->size--;

    return stack->boards[stack->size];

}

Here is my push

void push(BoardPtr b) {

    Board n = *b;

    stack->boards[stack->size] = n;
    stack->size++;

}

The thing is that the board put into the stack has to be separated or copied from the BoardPtr and put into the Stack so that I can make changes to the BoardPtr later on. Then when I pop it I set the BoardPtr to the last board from the stack.

How can I copy the Board without changing the pointer so I can save it into a stack?

code
  • 69
  • 1
  • 9
  • What is `Board`? What is `BoardPtr`? – John Apr 28 '15 at 02:27
  • Board is a stack that contains a 2D array of characters. And BoardPtr is a pointer to a Board – code Apr 28 '15 at 02:28
  • Can we see the `typedef`s for those? – John Apr 28 '15 at 02:29
  • 2
    Post a minimal correct example please. – 2501 Apr 28 '15 at 02:30
  • 3
    The scope of `result` is within the function it was defined. Memory allocated for it will be discarded and possibly reused for something else when the function returns. – alvits Apr 28 '15 at 02:32
  • @alvits I don't see what the problem is with result though. – code Apr 28 '15 at 02:34
  • 2
    your pop function should return to &stack->boards[stack->size] , not to address of a local variable. – Unavailable Apr 28 '15 at 02:37
  • @BoraBozkurt If I do that I can't subtract one from size to lower the stack though. Or can I? – code Apr 28 '15 at 02:39
  • @alvits, so don't try to learn anything if you can't learn it correctly ASAP? – Apprentice Queue Apr 28 '15 at 02:42
  • 3
    @code: alvits is correct: `Board result` is allocated locally to function "pop()", and goes out of scope when "op()" exits. This is Bad :( – FoggyDay Apr 28 '15 at 02:44
  • I changed my push and pop accordingly but I still get a segmentation fault and I don't know why. – code Apr 28 '15 at 02:47
  • I keep getting a segmentation fault related to push – code Apr 28 '15 at 02:55
  • if you just wanted to work on a copy-version of a board structure in stack, I posted a sample code below. On the other hand, If I were you, I would implement a dynamically allocated stack structure with altogether CreateStack, DeleteStack, Push and Pop functions. – Unavailable Apr 28 '15 at 03:15

2 Answers2

1

As others have pointed in the comments, the problem here is that you are returning the address of the local variable. This is bad, because it causes undefined behavior: in effect, you're accessing memory that no longer belongs to your program.

Here is your existing code, annotated to highlight the problem:

// Why are you passing a Board into pop? It's never used...
BoardPtr pop(Board b) {

    // result is a local variable - as soon as you leave the 
    // pop function, it disappears!
    // Also, assuming your indices are 0 based, then you are
    // returning the wrong thing: if stack->size is 1, you
    // want to return the item at position 0, not position 1!
    Board result = stack->boards[stack->size];
    stack->size--; //top is

    // Uh-oh! You are returning a pointer to result, which is
    // local. The value you return to the caller points to who-knows
    // what now!
    return &result;

}

The easiest solution is to change this function to not return a pointer to a Board, but the actual Board. Consider this:

Board pop() {
    assert (stack->size != 0);

    stack->size--;
    Board result = stack->boards[stack->size];
    return result;
} 

This works correctly because you aren't returning the local variable but a copy of it to the caller. I think that this is the best and safest option for you going forward. If you want to get fancy, you could try this version instead, which does the same thing:

Board pop() {
    assert (stack->size != 0);
    return stack->boards[--stack->size];
}

Alternatively, you could do something like this:

void pop(BoardPtr b) {
    assert (stack->size != 0);
    if (b != NULL)
        *b = stack->boards[--stack->size];
}

Caveat emptor: this last version, that accepts a BoardPtr may not work right if your struct contains pointers (see Shallow copy and deep copy in C. Yours doesn't, so this is fine.

Community
  • 1
  • 1
Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
  • I don't have a parameter in pop() – code Apr 28 '15 at 02:50
  • 1
    You did, when I copied the code. You don't now - isn't editing wonderful? – Nik Bougalis Apr 28 '15 at 02:51
  • I get a segmentation fault relating to push – code Apr 28 '15 at 02:56
  • @code, I understand how overwhelming debugging a program is, but the reality is that you need to learn how to walk through this logic and track down the errors yourself. You cannot just expect us to debug your entire program for you. Hint: pretend you are a computer that can execute C code directly. Try to execute your code using paper and pencil, one line at a time and make sure that things make sense at every step. When they don't, you'll have found your bug. If you _still_ can't find it, then come back, asking a new question. – Nik Bougalis Apr 28 '15 at 02:59
  • I don't. I did the rest of the program already. I just don't know if there is something wrong with how I am doing my push and pop – code Apr 28 '15 at 03:00
  • Hint: do you set `stack->size` to 0 when you start out? – Nik Bougalis Apr 28 '15 at 03:02
  • size starts at 0 yea – code Apr 28 '15 at 03:03
  • No, that's not what I'm asking. Do _you_, **explicitly** set it to 0 in your code? – Nik Bougalis Apr 28 '15 at 03:03
  • Earlier in the program when a board is created i set stack->size = 0; – code Apr 28 '15 at 03:04
  • Generally, "why isn't this code working" questions aren't allowed. I'll take a couple of guess, but I'll need to see your `main` function. – Nik Bougalis Apr 28 '15 at 03:07
  • I do this: stack = malloc(sizeof(struct stack_S)); – code Apr 28 '15 at 03:08
  • What's `struct stack_struct`? All I see in your code is `struct stack_S` – Nik Bougalis Apr 28 '15 at 03:09
1

If you want to preserve the base address of the board item that you want to modify its properties, you can simply copy that structure to an allocated memory region dynamically like the following:

{

 // ...

 Board realBoard = pop();                          // get Board structure at the top of your stack
 Board copyBoard = (Board*)malloc(sizeof(Board));  // allocate a Board structure in a new memory region

 memcpy(&copyBoard, &realBoard, sizeof(Board));      // simply copy it

 // do your operations on the copy version

 free(copyBoard);                                  // do not forget to free allocated memory

 // ...

}

EDIT: If you're storing copy versions of a Board structure in a Stack data structure and want to get the original one's base address, you may want to hold its memory address in every copy of it that you're storing in Stack

typedef struct tagBoard {

int rows; 
int cols;
char board[MAX_R][MAX_C];
struct tagBoard* OriginalBoardAddr;

} Board;

and your push function could be something like the following:

void push(const Board* ptr) {

stack->boards[stack->size++] = *ptr;

}

before pushing your Board (copy version) item to Stack, pass the address of the original one to store its address like the following:

{
   // Board real;   // the original Board that allocated in somewhere
   Board copy;      // the copy version that you're making differences and storing in a Stack structure

   // ...

   copy.OriginalBoardAddress = ℜ  // store original's address
   push(&copy);                        // push copy version to stack

}
Unavailable
  • 681
  • 4
  • 13
  • says it should be memcpy(&copyBoard, &realBoard, sizeof(Board)); – code Apr 28 '15 at 03:17
  • Ops, of course you should pass address of the structures to memcpy function. I forgot to write them, ok fixed it now. – Unavailable Apr 28 '15 at 03:22
  • Okay I will try this and tweak it to try to get it to work for my program. Thanks – code Apr 28 '15 at 03:22
  • I did this BBoardPtr copy = malloc(sizeof(b)); memcpy(copy, b, sizeof(BBoard)); BBoard temp = *copy; stack->top++; stack->boards[stack->top] = temp; – code Apr 28 '15 at 03:25
  • But the program crashes – code Apr 28 '15 at 03:25
  • You're welcome if you just wanted to work on a copy version of a board structure in your stack. But first, you need to implement your stack structure correctly. best regards. – Unavailable Apr 28 '15 at 03:26
  • Could you please tell me what you are exactly trying to accomplish? Correct me If I got you wrong. You're trying to implement a stack data structure that contains Board structures, right? And when you pop a Board from the stack, you do some operations on it then push it back to stack? In this case, your stack has already allocated a memory area for your board. If you push your popped one back,you will not have changed its base address unless these operations will not be sequential for just one Board. Otherwise,you need to do swap operations in your stack to make board get its previous address. – Unavailable Apr 28 '15 at 03:40
  • Basically push and pop these boards to a stack. With push taking a Board pointer – code Apr 28 '15 at 03:43
  • Well, why would you do something like that? You have already know your board's address in your stack. Just keep the index of the board that you're pushing, then you can get its address from the Stack. Something like this: push(int index, Board b); Board* addr = &stack.Boards[index]; or just simply put an index variable in Board structure. – Unavailable Apr 28 '15 at 03:49
  • But when i push it again i push the same address. And before i do push the board is changed elsewhere in my program. The stack stores all changes of the board so i can undo those changes – code Apr 28 '15 at 03:53
  • So you're just storing the different versions of a Board in a Stack structure, right? And the original Board is allocated in memory somewhere else in your process actually? Ok, if this is the case, then you should add a Board* variable in your Board structure that holds the original Board's address. – Unavailable Apr 28 '15 at 03:59
  • Along with my Board? Or change The Board i have to Board*? – code Apr 28 '15 at 04:00
  • in your board_struct. give me a second, i'll update my answer so you can see it there. – Unavailable Apr 28 '15 at 04:04