2013-12-09 110 views
1


我需要能夠用數據填寫我的my_s1結構。我將它傳遞給get_data()函數,該函數應該完成所有骯髒的工作。我遇到的問題是我的結構成員是指針。我不知道如何正確地分配(char *)buffb指向的值,而沒有分段錯誤或valgrind錯誤。
例如:將字符串賦值給C中的一個結構成員(指針)

  1. 爲什麼初始P1-> B = 「ABC」;工作正常,但如果我嘗試strcpy()或通過「=」運算符分配到p1-> b我得到錯誤?

  2. 是否S1 my_s1分配爲b內存還是應該我莫名其妙的malloc()P1-> b自己?但是,我又需要釋放()它並在從函數返回之前分配一個NULL指針,這違背了目的(使函數將數據分配給結構),對嗎?

  3. 有了下面列出我有「正確的執行結果」,但當前的代碼我也得到了以下的valgrind輸出誤差(從我的理解,請糾正我,如果我錯了,它好像的printf()訪問沒有正確分配內存 - 所以在這種情況下工作,但它是垃圾):

的valgrind:

==1067== Memcheck, a memory error detector 
==1067== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. 
==1067== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info 
==1067== Command: ./if 
==1067== Parent PID: 1059 
==1067== 
==1067== Invalid read of size 1 
==1067== at 0x4E7ADF9: vfprintf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4E83E38: printf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4005EF: main (iface.c:10) 
==1067== Address 0x51f3040 is 0 bytes inside a block of size 5 free'd 
==1067== at 0x4C294C4: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64- 
linux.so) 
==1067== by 0x40064D: get_data (ifacelib.c:17) 
==1067== by 0x4005D3: main (iface.c:8) 
==1067== 
==1067== Invalid read of size 1 
==1067== at 0x4EA9459: [email protected]@GLIBC_2.2.5 (in /usr/lib64/libc-2.17. 
so) 
==1067== by 0x4E7ADB1: vfprintf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4E83E38: printf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4005EF: main (iface.c:10) 
==1067== Address 0x51f3043 is 3 bytes inside a block of size 5 free'd 
==1067== at 0x4C294C4: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64- 
linux.so) 
==1067== by 0x40064D: get_data (ifacelib.c:17) 
==1067== by 0x4005D3: main (iface.c:8) 
==1067== 
==1067== Invalid read of size 1 
==1067== at 0x4EA946C: [email protected]@GLIBC_2.2.5 (in /usr/lib64/libc-2.17. 
so) 
==1067== by 0x4E7ADB1: vfprintf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4E83E38: printf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4005EF: main (iface.c:10) 
==1067== Address 0x51f3042 is 2 bytes inside a block of size 5 free'd 
==1067== at 0x4C294C4: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64- 
linux.so) 
==1067== by 0x40064D: get_data (ifacelib.c:17) 
==1067== by 0x4005D3: main (iface.c:8) 
==1067== 
==1067== Invalid read of size 4 
==1067== at 0x4EBBDDE: __GI_mempcpy (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4EA939C: [email protected]@GLIBC_2.2.5 (in /usr/lib64/libc-2.17. 
so) 
==1067== by 0x4E7ADB1: vfprintf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4E83E38: printf (in /usr/lib64/libc-2.17.so) 
==1067== by 0x4005EF: main (iface.c:10) 
==1067== Address 0x51f3040 is 0 bytes inside a block of size 5 free'd 
==1067== at 0x4C294C4: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64- 
linux.so) 
==1067== by 0x40064D: get_data (ifacelib.c:17) 
==1067== by 0x4005D3: main (iface.c:8) 
==1067== 
==1067== 
==1067== HEAP SUMMARY: 
==1067==  in use at exit: 0 bytes in 0 blocks 
==1067== total heap usage: 1 allocs, 1 frees, 5 bytes allocated 
==1067== 
==1067== All heap blocks were freed -- no leaks are possible 
==1067== 
==1067== For counts of detected and suppressed errors, rerun with: -v 
==1067== ERROR SUMMARY: 10 errors from 4 contexts (suppressed: 2 from 2) 

代碼在3個文件。

ifacelib.h:

#ifndef IFACELIB_H 
#define IFACELIB_H 

typedef struct 
{ 
    int a; 
    char * b; 
} s1; 

int get_data(s1 *); 

#endif 

ifacelib.c:

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

int get_data(s1 *p1) 
{ 
    char *buff; 
    p1->a=1; 
    p1->b="abc"; 

    buff = (char *) malloc(strlen("test")*sizeof(char)+1); 
    strcpy(buff, "test"); 

    p1->b = buff; 

    free(buff); 
    buff = NULL; 

    return 0; 
} 

iface.c:

#include "ifacelib.h" 
#include <stdio.h> 

int main() 
{ 
    s1 my_s1; 

    if ((get_data(&my_s1))==0) 
    { 
     printf("a= %d\tb= %s\n", my_s1.a, my_s1.b); 
    } 

    return 0; 
} 


任何幫助或只是在一個正確的方向指向,將不勝感激。


最佳實踐從一個角度來看,在處理結構時我應該寫一個函數來填充結構中的數據(處理傳遞的結構)並返回int來控制成功/失敗或者我應該寫一個函數返回一個修改後的結構呢?


這是我在這裏的第一篇文章,所以請忍受我,我的格式錯誤,文字牆和我的無知。
由於提前,
湯姆

+1

我懷疑你對指針指向在指針和事物之間的差異基本誤解。當你在C中「分配一個字符串」時,你只能分配指針。實際的字符數據不會移動。 –

+0

爲什麼在malloc之後立即釋放?您也可以在釋放緩衝區後訪問p1-> b! p1-> b只是一個指向緩衝區的指針,當你確定不再使用緩衝區時,你只能釋放緩衝區。 – moeCake

+0

非常感謝@moeCake,我不是在get_data()函數中釋放buff,而是在main()末尾釋放(my_s1.b),而不是獲取內存泄漏或valgrind錯誤。 – wymiata3

回答

1

你做錯了,只是幸運地得到正確的結果,其實你正在訪問剛剛被釋放的內存。
這是正確的,你必須在結構中的char *的malloc(順便說一句,你可以使用strdup),但你需要另一個析構函數來釋放結構,當他們的工作完成。
在你的情況下,你需要在printf之後使用free_s1之類的函數,而不是在構造函數(get_data)中釋放。

0

這個工作在C,C++中不那麼好:

如果你要的malloc(),它可能會更好的malloc既您結構和一重擊必殺的數據區。而不是讓指針在結構的最後安排一個最小的數據區域。在分配結構時添加額外的字節以允許數據。那麼你很好去。一個免費將釋放結構和數據。

重做代碼片段以顯示主要思想我得到以下內容。我留給學生編譯,調試,甚至語法檢查。

typedef struct 
{ 
    int a; 
    char * b; 
    char data[1]; // data goes here. 
         // structure MUST be malloced at run time WITH 
         // extra storage for data. 
} s1; 
 
    s1 *p1; 
    data = "test"; 
    data_len = strlen(data);  // additional bytes of storage 
    p1 = malloc(data_len + sizeof(*p1)); // allocate structure + data 
    strcpy(s1->data, data);  // copy data to buffer 

    ... 
    free(p1);  // free storage