C語言指針使用malloc的問題

最近在回顧C語言知識點時發現自己對指針的使用有些生疏了,把遇到的問題記錄下來,以加深對指針的理解。

首先看下面的示例,實現將字符串反轉輸出,如“abcdef”, 輸出爲“fedcba”, 實現起來是不是很簡單?
一開始我也這樣覺得,下面是我第一次實現的代碼:
int main(void)
{
    char *src = "Hello, World";
    char *dest = NULL;
    int len = 0;

    len = strlen(src);
    dest = (char *)malloc(len+1);
    if (dest == NULL) {
        printf("dest malloc failed.\n");
        return 0;
    }

    while (len-- != 0) {
        *dest++ = src[len];
    }

    *dest = 0;

    printf(“Sting dest: %s\n”, dest);
    free(dest);

    return 0;
}

看起開沒問題,使用gcc -o test test.c也順利編譯通過了,但執行./test時發現竟然報錯了,錯誤如下:
*** Error in `./test_bak': munmap_chunk(): invalid pointer: 0x00000000023f201c ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f931d8317e5]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x1a8)[0x7f931d83e698]
./test_bak[0x40068e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f931d7da830]
./test_bak[0x400529]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 1325569                            /home/lipf/works/C_Project/lesson/lesson_1/test_bak
00600000-00601000 r--p 00000000 08:01 1325569                            /home/lipf/works/C_Project/lesson/lesson_1/test_bak
00601000-00602000 rw-p 00001000 08:01 1325569                            /home/lipf/works/C_Project/lesson/lesson_1/test_bak
023f2000-02413000 rw-p 00000000 00:00 0                                  [heap]
7f931d5a4000-7f931d5ba000 r-xp 00000000 08:01 1444647                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f931d5ba000-7f931d7b9000 ---p 00016000 08:01 1444647                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f931d7b9000-7f931d7ba000 rw-p 00015000 08:01 1444647                    /lib/x86_64-linux-gnu/libgcc_s.so.1
跟蹤代碼發現時free(dest)時報了“invalid pointer: 0x00000000023f201c ”的錯誤,當時有點不太理解爲什麼會報這樣的錯誤,malloc分配也成功了,沒理由會報非法指針的錯誤。先把free()這裏屏蔽掉,看看結果是否如預期的那樣,結果發現打印的dest爲空,這是爲什麼呢?
進一步添加printf打印信息,如下:
    while (len-- != 0) {
        printf("dest point addr: %p\n", dest);
        *dest++ = src[len];
        printf("src char: %c\n", src[len]);
        printf("dest char: %c\n", *dest);
    }
將dest的地址以及存放的值打印出來,結果如下:
dest point addr: 0xdb2010
src char: d
dest char:
dest point addr: 0xdb2011
src char: l
dest char:
dest point addr: 0xdb2012
src char: r
dest char:
dest point addr: 0xdb2013
src char: o
dest char:
dest point addr: 0xdb2014
src char: W
dest char:
dest point addr: 0xdb2015
src char:  
dest char:
dest point addr: 0xdb2016
src char: ,
dest char:
dest point addr: 0xdb2017
src char: o
dest char:
dest point addr: 0xdb2018
src char: l
dest char:
dest point addr: 0xdb2019
src char: l
dest char:
dest point addr: 0xdb201a
src char: e
dest char:
dest point addr: 0xdb201b
src char: H
dest char:
String dest:

從打印的log可看出dest的值在改變,這裏就涉及到了使用malloc()函數分配內存的問題,malloc返回的是分配內存的首地址,所以使用free釋放內存時也應該是一開始分配的內存首地址,而示例中執行了*dest++,導致dest的值發生了變化,所以在執行free(dest)時會報錯。
那要如何修正錯誤呢?下面提供了兩種方法。
方法一:dest指針使用數組的形式
    int i=0;

    while (len-- != 0) {
        dest[i] = src[len];
        i++;
    }

    dest[len] = '\0';

    printf("dest String: %s\n", dest);
    free(dest);

方法二:使用指針
    dest = (char *)malloc(len + 1);
    char *tmp = dest;

    while (len-- != 0) {
        *tmp++ = src[len];
    }

    *tmp = '\0';

    printf("dest String: %s\n", dest);
    free(dest);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章