2017-03-31 25 views
1

好的快速介紹。我正在做動態分配內存的功課。我們需要使用結構體和dyn來模擬CPU。人。記憶。我正在測試我的堆棧是否正常運行並且不會溢出。該堆棧應該是2 KiB,沒有溢出,但在打印數字時,很少有地址包含其他數字,我沒有放入。我只是在這裏複製它,並擺脫指令列表,寄存器等,這不是一個問題,並會使這個很長。從動態分配的內存打印時值發生變化

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

struct cpu { 
    struct stack* memory; 
}; 

struct stack { 
    int32_t* values; 
    int32_t* top; 
}; 

void stackInit(struct stack* stack) 
{ 
    stack->values = malloc(2048); 
    stack->top = NULL; 
} 

void cpuInit (struct cpu* cpu) 
{ 
    stackInit(cpu->memory); //initialize stack 
} 

void stackPush(struct stack* stack, int32_t value) 
{ 
    if (stack->top == NULL){ 
     stack->top = stack->values; 
     *(stack->top) = value; 
    } 
    else if (stack->top + sizeof(int32_t) < stack->values + 2048){ 
     stack->top += sizeof(int32_t); 
     *(stack->top) = value; 
    } 
} 

void cpuDebug(const struct cpu* cpu) 
{  
    int32_t* auxpt = cpu->memory->top; 

    if (cpu->memory->top != NULL) 
     for (int32_t i = 0; auxpt >= cpu->memory->values; i++){ 

      printf("Value on the addr %d\n", *auxpt); 
      printf("Address of auxpt: %p\n", (void *)auxpt); 
      auxpt -= sizeof(int32_t); 
     } 

    printf("\n"); 
} 

int main() 
{ 
    struct cpu Cpu; 

    cpuInit(&Cpu); 

    for (int32_t i = 0; i < 550; i++){ 
     stackPush(Cpu.memory,i); 
    } 

    cpuDebug(&Cpu); 

    return 0; 
} 

和輸出是這樣的:

Value on the addr 133 
Address of auxpt: 0x562640529880 
Value on the addr 10 
Address of auxpt: 0x562640529870 
Value on the addr 544108298 
Address of auxpt: 0x562640529860 
Value on the addr 2016419898 
Address of auxpt: 0x562640529850 
Value on the addr 1919181889 
Address of auxpt: 0x562640529840 
Value on the addr 128 
Address of auxpt: 0x562640529830 
Value on the addr 127 

任何想法,爲什麼會出現這種情況? 在此先感謝

+2

'stack-> values + 2048'返回比'stack-> values'更高的地址'2048 * 4'個字節。這遠遠超出了分配的空間。指針算術是棘手的,這就是爲什麼你更好地使用數組符號和適當的類型。 –

+1

你正在處理棧結構中的一個指向'int32_t'的指針......所以當你添加/減去它時,它的單位是sizeof(int32_t)'字節,而不是單個字節。所以,例如。 'stack-> top + = sizeof(int32_t);'增加sizeof(int32_t)* sizeof(int32_t)'字節,而不僅僅是'sizeof(int32_t)'字節。 – Dmitri

+0

非常感謝。我記得那件事。 – St4lker

回答

3

struct cpu具有關聯struct stack,但堆棧不是的struct cpu部分; CPU只保存一個指向單獨堆棧的指針。你永遠不會初始化那個指針,也不會爲所需的棧保留任何內存。特別是,您的cpuInit()函數不會這樣做,並且您的stackInit()函數取決於它已經完成。

總體來看,假設每個CPU需要它的壽命只有一個堆棧,你會過得更好使堆棧中的CPU的一個組成部分,所以你不必擔心這樣的分配問題:

struct cpu { 
    struct stack memory; // not a pointer 
}; 

這樣做後,您需要更改通過cpu訪問堆棧成員的語法,並且需要注意其他語義差異,但是您始終可以獲取指向堆棧的指針在需要時(例如通過stackInit())通過&運營商。

+0

是的,謝謝你指出,它不應該是一個指針,我的壞。再次感謝你:)我們剛剛學過指針,並且在代碼中有很多'*',我開始將它們放在任何地方:D – St4lker

4

人,你必須訪問之前分配結構棧及其成員(頂部)。您正在訪問非mallocated內存。

void stackInit(struct stack* stack) 
{ 
    stack = malloc(sizeof(struct stack)); 
    stack->values = malloc(2048); 
    stack->top = NULL; 
} 

繼招數在評論中指出,一個更好的解決方案可能是:

void stackInit(struct stack** stack) 
{ 
    (*stack) = (struct stack*)malloc(sizeof(struct stack)); 
    (*stack)->values = (int32_t*)malloc(2048); 
    (*stack)->top = NULL; 
} 

void cpuInit(struct cpu* cpu) 
{ 
    stackInit(&cpu->memory); //initialize stack 
} 

通過這種方式,調用者可以分配的內存中Cpu.memory的情況下。

+2

你是對的,但這是行不通的,因爲調用函數不會得到'stack'的新值。 –

+0

爲什麼不能,指針在stackInit外部是'可見的',因爲是指針而不是副本,調用者將現在對待一個mallocated的內存,是不是? – Pablo

+0

不,@Pablo。 *指針指向的*在別處通過其他指針副本可見。指針值本身就是一個像其他值一樣的值 - 「stackInit()」接收調用者值的副本,並且對函數副本的更改不會自動傳回給調用者。 –