เรื่องของ Stack และ Heap

วันนี้เป็นอีกวันที่เขียน C อย่างเมามัน และไปงงกับ Error แปลกๆอยู่หลายชั่วโมง เหตุเพราะอยากได้ข้อมูลที่มีพื้นที่ของหน่วยความจำที่ต่อเนื่องกัน ในตอนแรกจึงเลือกใช้ static array สำหรับเก็บค่า ซึ่งตอนหลังก็พบว่าไม่จำเป็นต้องใช้

ลองมาดูตัวอย่างกันดีกว่า

มี function หนึ่ง return ค่า string  หรือถ้าเรียกให้ถูกคือ  address ของหน่วยความจำที่เก็บ string แต่ค่าที่ได้มันกลายเป็นภาษาขยะ ยกตัวอย่างง่ายๆจาก code ด้านล่าง ซึ่งจะ print ตัวอักษร A สิบตัวอักษร

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

char *
get_var()
{
    char x[11];

    memset(x,65 /*A*/,10);
    x[10] = '\0';

    printf("get_var()\n");
    printf("%s\n", x);

    return x;
}

int
main()
{
    char * y;

    y = get_var();

    printf("%s\n", y);

    return 0;
}

หลังจาก compile และ run ได้ค่าแบบนี้

$ gcc x.c -o x
$ ./x
get_var()
AAAAAAAAAA
��Y��do

เมื่อ print ตัวแปร x ใน function get_var() ออกมา มันก็ออกมาอย่างที่ควรจะเป็น แต่พอ ค่าของตัวแปร y ที่อยู่ใน main() ซึ่งรับมาจาก get_var() อีกทีมันดันออกมาเป็นขยะ

คราวนี้ลองมาดูของที่ถูกดูบ้าง

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

char *
get_var()
{
    char * x;
    x = (char *) malloc(11);

    memset(x,65 /*A*/,10);
    x[10] = '\0';

    printf("get_var()\n");
    printf("%s\n", x);

    return x;
}

int
main()
{
    char * y;

    y = get_var();

    printf("%s\n", y);

    free(y);

    return 0;
}

$ gcc x.c -o x
$ ./x
get_var()
AAAAAAAAAA
AAAAAAAAAA

คราวนี้ค่าที่ได้ออกมาถูกต้อง

ในตัวอย่างแรกเวลา compile จะมี warning แบบนี้
x.c:19: warning: function returns address of local variable

ซึ่งถ้าเราไม่ทันสังเกตุ หรือไม่สนใจว่ามันคืออะไร มันก็จะเกิดปัญหาแบบที่ผมเป็น

อธิบายง่ายๆว่า การประกาศตัวแปร char x[11]; ในตัวอย่างแรกนั้น address ของ x จะถูกเก็บอยู่ใน stack ของ get_var() ซึ่งไม่สามารถอ้างถึงได้จาก function อื่น พอ function get_var() return ค่าข้อมูลใน stack ของ get_var() ก็หายหมด ทำให้ค่า address ของหน่วนความจำที่ใน function main() รับมาไม่มีอยู่จริง pointer ก็ไปชี้อะไรมั่วซั่ว เวลา print ออกมาดูทำให้ได้ขยะมาอย่างที่เห็น

วิธีแก้ก็ง่ายๆคือ ใช้ตัวแปรที่เก็บใน Heap

char * x;
x = (char *) malloc(11);

เมื่อ get_var() return address ของหน่วยความจำออกมา function อื่นก็ยังสามารถอ้างถึงได้ แต่เมื่อใช้เสร็จต้องคืน memory โดยใช้คำสั่ง free() ด้วย

About these ads

2 คิดบน “เรื่องของ Stack และ Heap

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s