2013-12-09 72 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