C 在结构中重新指定元素(特别是指针)

C 在结构中重新指定元素(特别是指针),c,pointers,struct,C,Pointers,Struct,我想获取一个结构,“垃圾”它,并重新分配其元素的值。我编写了下面的示例代码,它似乎可以工作。但我想知道是否有人认为它有什么问题。我主要担心的是“名称”和“ip”指针。他们出来的时候看起来不错,但我只是运气好吗 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct stuff_s{ int n; char *name; int dsize;

我想获取一个结构,“垃圾”它,并重新分配其元素的值。我编写了下面的示例代码,它似乎可以工作。但我想知道是否有人认为它有什么问题。我主要担心的是“名称”和“ip”指针。他们出来的时候看起来不错,但我只是运气好吗

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


typedef struct stuff_s{

   int n;
   char *name;
   int dsize;
   int *ip;

} stuff;


void output_stuff(stuff *s){

   int n;

   printf("%d\n", s->n);
   printf("%s\n", s->name);
   printf("%d\n", s->dsize);

   for (n=0; n<s->dsize; n++) {
      printf("%d ",s->ip[n]);
   }

   printf("\n");

}


void reassign(stuff *s) {

   stuff snew;
   int n;

   snew.n = 2;
   snew.name = calloc(32, sizeof(char));
   strcpy(snew.name, "Snoopy");
   snew.dsize = 12;
   snew.ip = calloc(snew.dsize, sizeof(int));
   for (n=0; n<snew.dsize; n++) { snew.ip[n] = n; }

   free(s->name);
   free(s->ip);

   memcpy(s, &snew, sizeof(stuff));

}


int main() {

   stuff d;
   int n;

   d.n = 1;
   d.dsize = 10;
   d.ip = calloc(d.dsize, sizeof(int));
   for (n=0; n<d.dsize; n++) {
      d.ip[n] = n;
   } 
   d.name = calloc(32, sizeof(char));
   strcpy(d.name,"Charlie Brown");

   output_stuff(&d);
   printf("\n");

   reassign(&d);

   output_stuff(&d);

   free(d.ip);
   free(d.name);

}
#包括
#包括
#包括
typedef struct stuff\s{
int n;
字符*名称;
int-dsize;
int*ip;
}东西;
无效输出内容(内容*s){
int n;
printf(“%d\n”,s->n);
printf(“%s\n”,s->name);
printf(“%d\n”,s->dsize);
对于(n=0;ndsize;n++){
printf(“%d”,s->ip[n]);
}
printf(“\n”);
}
无效重新分配(物料*s){
新事物;
int n;
snew.n=2;
snew.name=calloc(32,sizeof(char));
strcpy(snew.name,“史努比”);
snew.dsize=12;
snew.ip=calloc(snew.dsize,sizeof(int));
对于(n=0;nname);
免费(s->ip);
memcpy(s&snew,sizeof(stuff));
}
int main(){
材料d;
int n;
d、 n=1;
d、 dsize=10;
d、 ip=calloc(d.dsize,sizeof(int));
对于(n=0;n嗯,下面是这样说的:

因此没有内存错误

一些文体要点

  • 您不需要使用
    sizeof(char)
    ——它被定义为1
  • dsize
    应该是无符号的,实际上应该是
    size\u t
    ,它比
    int
  • 正如SoronellHaetir指出的,您不需要使用另一个结构-您可以修改传入的结构
  • 好吧,这里是这样说的:

    因此没有内存错误

    一些文体要点

  • 您不需要使用
    sizeof(char)
    ——它被定义为1
  • dsize
    应该是无符号的,实际上应该是
    size\u t
    ,它比
    int
  • 正如SoronellHaetir指出的,您不需要使用另一个结构-您可以修改传入的结构
  • 我运气好吗?

    你很幸运,但不是因为你想的原因

    您对stuct分配和重新分配的处理是正确的,但不完整。您应该验证所有内存分配,以确保在分配失败时,您不会试图访问不属于您的内存,从而调用未定义的行为

    例如,当您分配
    d.ip
    --时,请检查返回值以确保
    calloc
    成功,例如

        if (!(d.ip = calloc (d.dsize, sizeof *d.ip))) {
            perror ("calloc d.ip failed");
            exit (EXIT_FAILURE);
        }
    
    每次分配都应该这样做

    重新分配
    键入
    void
    是不够的。它无法提供有意义的方法来确定函数中的分配是否成功。在分配内存、打开文件、获取输入等任何时候,请确保您声明的函数的类型可以提供有意义的返回以指示成功或失败失败。返回有效地址或
    NULL
    的指针可以工作,整数类型返回的值可以指示成功/失败

    不要在代码中使用幻数。如果您需要一个常量,例如
    名称
    成员的大小,那么
    #定义一个或使用一个
    枚举
    。例如,如果您希望
    名称
    的大小为
    32
    字节,那么请定义一个名称常量,例如

    #define NMSZ 32
    
    您的
    重新分配
    功能继续使用神奇的数字和神奇的字符串为
    .n
    .dsize
    .dname
    分配任务(当然,我知道这可能需要快速测试).通过将
    n
    name
    dsize
    的值作为函数参数传递,使
    重新分配
    变得有用

    您不需要
    memcpy(s,&snew,sizeof(stuff))
    。您需要做的就是赋值
    *s=snew;
    。现在您可能有点幸运,因为您将结构的指针成员限制为单指针。由于包含的值是每个内存块的起始地址,因此只需赋值。但是,如果您将指向类型的指针用作成员(例如双指针)赋值(或
    memcpy
    )不再足够,需要深度拷贝

    注意:除非您需要
    名称
    可修改(例如,您需要更改单个字符),否则可以使用字符串文字,无需完全动态分配

    将您选择的
    int n;
    更改为
    int i;
    作为计数器也可能是明智的,以消除
    n
    s.n
    之间的混淆

    将这些部分放在一起,您可以使
    重新分配
    更加健壮,如下所示:

    stuff *reassign (stuff *s, int n, const char *name, int dsize) {
    
        stuff snew;
        int i;
    
        snew.n = n; /* validate all memory allocations */
        if (!(snew.name = calloc (NMSZ, sizeof *snew.name))) {
            perror ("calloc snew.name");
            return NULL;
        }
        strcpy (snew.name, name);
    
        snew.dsize = dsize; /* ditto */
        if (!(snew.ip = calloc (snew.dsize, sizeof *snew.ip))) {
            perror ("calloc snew.ip");
            return NULL;
        }
    
        for (i = 0; i < snew.dsize; i++)
            snew.ip[i] = i + 5;
    
        free (s->name);
        free (s->ip);
    
        *s = snew;  /* you can simply assign snew */
    
        return s;
    }
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define NMSZ 32
    
    typedef struct stuff_s {
        int n,
            dsize,
            *ip;
        char *name;
    } stuff;
    
    
    void output_stuff (stuff *s){
    
        int n;
    
        printf ("%d\n%s\n%d\n", s->n, s->name, s->dsize);
    
        for (n = 0; n < s->dsize; n++)
            printf ("%d ",s->ip[n]);
    
        putchar ('\n');
    }
    
    
    stuff *reassign (stuff *s, int n, const char *name, int dsize) {
    
        stuff snew;
        int i;
    
        snew.n = n; /* validate all memory allocations */
        if (!(snew.name = calloc (NMSZ, sizeof *snew.name))) {
            perror ("calloc snew.name");
            return NULL;
        }
        strcpy (snew.name, name);
    
        snew.dsize = dsize; /* ditto */
        if (!(snew.ip = calloc (snew.dsize, sizeof *snew.ip))) {
            perror ("calloc snew.ip");
            return NULL;
        }
    
        for (i = 0; i < snew.dsize; i++)
            snew.ip[i] = i + 5;
    
        free (s->name);
        free (s->ip);
    
        *s = snew;  /* you can simply assign snew */
    
        return s;
    }
    
    int main() {
    
        stuff d = { .n = 1, .dsize = 10 };
        int i;
    
        if (!(d.ip = calloc (d.dsize, sizeof *d.ip))) {
            perror ("calloc d.ip failed");
            exit (EXIT_FAILURE);
        }
        for (i = 0; i < d.dsize; i++)
            d.ip[i] = i;
    
        if (!(d.name = calloc (NMSZ, sizeof *d.name))) {
            perror ("calloc d.name failed");
            exit (EXIT_FAILURE);
        }
        strcpy (d.name, "Charlie Brown");
    
        output_stuff (&d);
        putchar ('\n');
    
        if (reassign (&d, 2, "Linus", 12)) {
    
            output_stuff (&d);
    
            free (d.ip);
            free (d.name);
        }
    
        return 0;
    }
    
    最后,如注释中所述,无需调用
    printf(“\n”);
    来输出单个字符。这就是
    putchar('\n');
    的目的。诚然,一个像样的编译器会为您进行优化,但这并不是不使用正确工具开始作业的借口

    将所有部分放在一起,您可以通过添加验证并使用
    重新分配的有意义返回,使代码更加健壮,并防止未定义的行为,如下所示:

    stuff *reassign (stuff *s, int n, const char *name, int dsize) {
    
        stuff snew;
        int i;
    
        snew.n = n; /* validate all memory allocations */
        if (!(snew.name = calloc (NMSZ, sizeof *snew.name))) {
            perror ("calloc snew.name");
            return NULL;
        }
        strcpy (snew.name, name);
    
        snew.dsize = dsize; /* ditto */
        if (!(snew.ip = calloc (snew.dsize, sizeof *snew.ip))) {
            perror ("calloc snew.ip");
            return NULL;
        }
    
        for (i = 0; i < snew.dsize; i++)
            snew.ip[i] = i + 5;
    
        free (s->name);
        free (s->ip);
    
        *s = snew;  /* you can simply assign snew */
    
        return s;
    }
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define NMSZ 32
    
    typedef struct stuff_s {
        int n,
            dsize,
            *ip;
        char *name;
    } stuff;
    
    
    void output_stuff (stuff *s){
    
        int n;
    
        printf ("%d\n%s\n%d\n", s->n, s->name, s->dsize);
    
        for (n = 0; n < s->dsize; n++)
            printf ("%d ",s->ip[n]);
    
        putchar ('\n');
    }
    
    
    stuff *reassign (stuff *s, int n, const char *name, int dsize) {
    
        stuff snew;
        int i;
    
        snew.n = n; /* validate all memory allocations */
        if (!(snew.name = calloc (NMSZ, sizeof *snew.name))) {
            perror ("calloc snew.name");
            return NULL;
        }
        strcpy (snew.name, name);
    
        snew.dsize = dsize; /* ditto */
        if (!(snew.ip = calloc (snew.dsize, sizeof *snew.ip))) {
            perror ("calloc snew.ip");
            return NULL;
        }
    
        for (i = 0; i < snew.dsize; i++)
            snew.ip[i] = i + 5;
    
        free (s->name);
        free (s->ip);
    
        *s = snew;  /* you can simply assign snew */
    
        return s;
    }
    
    int main() {
    
        stuff d = { .n = 1, .dsize = 10 };
        int i;
    
        if (!(d.ip = calloc (d.dsize, sizeof *d.ip))) {
            perror ("calloc d.ip failed");
            exit (EXIT_FAILURE);
        }
        for (i = 0; i < d.dsize; i++)
            d.ip[i] = i;
    
        if (!(d.name = calloc (NMSZ, sizeof *d.name))) {
            perror ("calloc d.name failed");
            exit (EXIT_FAILURE);
        }
        strcpy (d.name, "Charlie Brown");
    
        output_stuff (&d);
        putchar ('\n');
    
        if (reassign (&d, 2, "Linus", 12)) {
    
            output_stuff (&d);
    
            free (d.ip);
            free (d.name);
        }
    
        return 0;
    }
    
    如果你有任何进一步的问题,请仔细查看并告诉我

    我运气好吗?

    你很幸运,但不是因为你想的原因

    您对stuct分配和重新分配的处理是正确的,但不完整。您应该验证所有内存分配,以确保在分配失败时,您不会试图访问不属于您的内存,从而调用未定义的行为

    例如,当您分配
    d.ip
    --时,请检查返回值以确保
    calloc
    成功,例如

        if (!(d.ip = calloc (d.dsize, sizeof *d.ip))) {
            perror ("calloc d.ip failed");
            exit (EXIT_FAILURE);
        }
    
    对于每个分配,您都应该这样做