如何动态分配struct + pointer

5uzkadbs  于 2023-05-16  发布在  其他
关注(0)|答案(3)|浏览(204)

我一直在尝试找出如何将来自用户的信息存储在struct的数组中,但到目前为止。。不工作。
我创建了一个结构体,在main函数中我创建了一个指向这个结构体的指针,然后动态地分配这个结构体。但我真的不知道我将如何从用户那里获得信息,我的意思是。我知道,但它并不像预期的那样工作。如果我只使用一个struct数组,它会像这样...
&p[i].id //正常
我试着用这个方法,但不工作,idk为什么...代码还没有完成…

//
//  7.c
//  IFTM Exercises
//
//  Created by Lelre Ferreira on 8/29/19.
//  Copyright © 2019 Lelre Ferreira. All rights reserved.
//

#define size 5
#include <stdio.h>
#include <stdlib.h>

struct produtos {

    int id;
    int quant;
    float vlrs;
    char nm[50];

};

void cadastroProdutos (struct produtos *p, int tamanho);
void maiorValorProdutos (struct produtos *p, int tamanho);
void maiorEstoqueProdutos (struct produtos *p, int tamanho);

int main (int argc, const char * argv[]){

    struct produtos *p;
    int tamanho    = 0;

    printf("Insira quantidade de produtos/itens a serem cadastrados: ");
    scanf("%d", &tamanho);
    p = (struct produtos *) malloc(tamanho   * sizeof(struct produtos));

    cadastroProdutos(p, tamanho);
    maiorValorProdutos(p, tamanho);
    maiorEstoqueProdutos(p, tamanho);

    return 0;
}

void cadastroProdutos(struct produtos *p, int tamanho){

    int i = 0;
    for (i = 0; i < tamanho; i++) {

        printf("Insira o ID: ");
        scanf("%d", &p[i] -> id);
        printf("Insira o nome: ");
        scanf("%s",  p[i] -> nm);
        printf("Insira o valor: ");
        scanf("%f", &p[i] -> vlrs);
        printf("Insira a quantidade: ");
        scanf("%d", &p[i] -> quant);

    }
}

void maiorValorProdutos(struct produtos *p, int tamanho){


}

void maiorEstoqueProdutos(struct produtos *p, int tamanho){


}

IDE出现此错误:无法获取类型为“int”的右值的地址...

g9icjywg

g9icjywg1#

您没有理解[..]运算符应用于您的指针p(例如:p[0])作为解引用,使类型struct produtos'.'运算符正确(而不是@MilesBudnek的回答中提到的struct produtos*
除了'.''->'操作符问题之外,您似乎还没有注意到动态分配的要点。虽然从#define size 5分配的结构体开始很好,但动态分配内存的要点是能够无缝地处理第6个结构体,方法是根据需要重新分配额外的内存来处理所有输入(或者直到可用内存耗尽)。
你现在写的函数cadastroProdutos,并不能真正实现一个干净的动态分配(除了它返回void,并且没有验证其中的任何输入)。与在函数中循环size次不同,您只想在每次调用cadastroProdutos时获得相当于1个结构体的数据。这样,您可以根据需要多次调用它,直到输入所有数据。在你的函数中不需要循环,而且你对scanf的使用是非常脆弱的,因为你没有办法处理由于 * 匹配失败 * 或只是意外输入的流浪字符而留在stdin中的字符(例如:为id键入的'a',或长于49字符的名称等)
要解决大多数问题,不要对User-Input使用scanf,而是将所有User-Input读取到一个合理大小的临时缓冲区(例如:1024字符左右),然后使用sscanf从缓冲区解析所需的信息。这样做有双重好处:允许对读取和解析进行单独验证;通过使用合理大小的缓冲区,每次消耗一整行输入,就可以消除无关字符问题(例如猫踩在键盘上)。
你的cadastroProdutos接受输入,没有提供有意义的返回来指示输入的成功/失败,如果任何一个输入失败,你的函数容易受到 * 未定义行为 * 的影响。因此,通过检查所使用的函数的返回值来验证每个用户输入。对于任何输入失败,对于 failure 返回0,对于 success 返回非零值,允许您在调用函数中处理任何输入失败。
(**注意:**计数类型应该使用size_t,而不是int
将这些更改放在cadastroProdutos中,您可以执行类似于以下操作:

size_t cadastroProdutos (produtos *p, size_t *tamanho)
{
    produtos tmp;       /* temporary struct */
    char buf[MAXC];     /* temporary buffer */

    /* prompt, read-line, validate parse */
    fputs ("\nInsira o ID: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%d", &tmp.id) != 1)
        return 0;   /* (failure) */

    fputs ("Insira o nome: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%49[^\n]", tmp.nm) != 1)
        return 0;

    fputs ("Insira o valor: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%f", &tmp.vlrs) != 1)
        return 0;

    fputs ("Insira a quantidade: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%d", &tmp.quant) != 1)
        return 0;

    p[(*tamanho)++] = tmp;  /* assign tmp to p[*tamanho], increment */

    return *tamanho;    /* return tamanho (success) */
}

注意:tamanho作为指针传递,这样它的数字可以在函数内更新,失败时返回0,而成功时返回更新的tamanho,允许您有意义地返回size_t类型)
避免在代码中使用 magic-numbers。你为size定义了一个常数,现在只需要定义你需要的常数,这样就不会再有像char nm[50];这样的 * 魔法数字 * 了。要做到这一点,您可以使用更多的#define,例如。

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

#define PROD 2      /* initial no. of struct to allocate */
#define NMSZ 50     /* max name size */
#define MAXC 1024   /* reasonable no. of chars for temporary buffer */

typedef struct {    /* a typedef used for convenience */
    int id;
    int quant;
    float vlrs;
    char nm[NMSZ];
} produtos;

现在,您需要在main()中声明一个临时缓冲区来保存该行,以及size_t值,即当前分配的结构体总数(allocated)和填充的数字(tomanho),这导致在每个循环if (tomanho == allocated)的开始处的简单检查,你知道你需要realloc额外的结构体之前,试图填补任何更多。main()函数基本上可以是:

int main (void) {

    size_t  allocated = PROD,   /* initial number of struct to allocate */
            tomanho = 0;        /* number of allocated structs used */
    produtos *p = malloc (allocated * sizeof *p);   /* allocate */

    if (!p) {   /* validate EVERY allocation */
        perror ("malloc-p");
        return 1;
    }

    while (cadastroProdutos (p, &tomanho)) {    /* loop validating return */
        char buf[MAXC];                         /* buffer for input (y/n) */
        if (tomanho == allocated) { /* is a realloc needed to add struct? */
            /* always realloc with a temporary pointer */
            void *tmp = realloc (p, 2 * allocated * sizeof *p);
            if (!tmp) {     /* validate the reallocation */
                perror ("realloc-p");
                break;      /* realloc failed, original p still good, break */
            }
            p = tmp;        /* assign new block of mem to p */
            allocated *= 2; /* update no. of structs allocated */
        }

        fputs ("\n  add another (y/n)? ", stdout);  /* add more produtos? */
        if (!fgets (buf, MAXC, stdin) || !(*buf == 'y' || *buf == 'Y')) {
            putchar ('\n');
            break;
        }
    }

在这一点上,你所有的结构体都被填充并存储在p中,你需要做的就是你需要做的任何事情(简单地在下面输出),然后free()你已经分配的内存,例如:

for (size_t i = 0; i < tomanho; i++)    /* loop showing stored data */
        printf ("p[%2zu] %4d  %-20s  %6.2f  %4d\n",
                i, p[i].id, p[i].nm, p[i].vlrs, p[i].quant);

    free (p);   /* don't forget to free memory you allocate */
}

在一个简短的例子中,你可以这样做:

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

#define PROD 2      /* initial no. of struct to allocate */
#define NMSZ 50     /* max name size */
#define MAXC 1024   /* reasonable no. of chars for temporary buffer */

typedef struct {    /* a typedef used for convenience */
    int id;
    int quant;
    float vlrs;
    char nm[NMSZ];
} produtos;

size_t cadastroProdutos (produtos *p, size_t *tamanho)
{
    produtos tmp;       /* temporary struct */
    char buf[MAXC];     /* temporary buffer */

    /* prompt, read-line, validate parse */
    fputs ("\nInsira o ID: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%d", &tmp.id) != 1)
        return 0;   /* (failure) */

    fputs ("Insira o nome: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%49[^\n]", tmp.nm) != 1)
        return 0;

    fputs ("Insira o valor: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%f", &tmp.vlrs) != 1)
        return 0;

    fputs ("Insira a quantidade: ", stdout);
    if (!fgets (buf, MAXC, stdin) || sscanf (buf, "%d", &tmp.quant) != 1)
        return 0;

    p[(*tamanho)++] = tmp;  /* assign tmp to p[*tamanho], increment */

    return *tamanho;    /* return tamanho (success) */
}

int main (void) {

    size_t  allocated = PROD,   /* initial number of struct to allocate */
            tomanho = 0;        /* number of allocated structs used */
    produtos *p = malloc (allocated * sizeof *p);   /* allocate */

    if (!p) {   /* validate EVERY allocation */
        perror ("malloc-p");
        return 1;
    }

    while (cadastroProdutos (p, &tomanho)) {    /* loop validating return */
        char buf[MAXC];                         /* buffer for input (y/n) */
        if (tomanho == allocated) { /* is a realloc needed to add struct? */
            /* always realloc with a temporary pointer */
            void *tmp = realloc (p, 2 * allocated * sizeof *p);
            if (!tmp) {     /* validate the reallocation */
                perror ("realloc-p");
                break;      /* realloc failed, original p still good, break */
            }
            p = tmp;        /* assign new block of mem to p */
            allocated *= 2; /* update no. of structs allocated */
        }

        fputs ("\n  add another (y/n)? ", stdout);  /* add more produtos? */
        if (!fgets (buf, MAXC, stdin) || !(*buf == 'y' || *buf == 'Y')) {
            putchar ('\n');
            break;
        }
    }

    for (size_t i = 0; i < tomanho; i++)    /* loop showing stored data */
        printf ("p[%2zu] %4d  %-20s  %6.2f  %4d\n",
                i, p[i].id, p[i].nm, p[i].vlrs, p[i].quant);

    free (p);   /* don't forget to free memory you allocate */
}

(**注意:**增加了一个简单的add another (y/n)?提示,以确定用户是否需要添加更多数据)

示例使用/输出

上面我们从2-allocated结构开始,然后进入6结构,强制重新分配。例如:

$ ./bin/produtos

Insira o ID: 1
Insira o nome: John Brown
Insira o valor: 12.34
Insira a quantidade: 415

  add another (y/n)? y

Insira o ID: 2
Insira o nome: Mary Brown
Insira o valor: 23.45
Insira a quantidade: 416

  add another (y/n)? y

Insira o ID: 3
Insira o nome: Mickey Mouse
Insira o valor: 34.56
Insira a quantidade: 417

  add another (y/n)? y

Insira o ID: 4
Insira o nome: Minnie Mouse
Insira o valor: 45.67
Insira a quantidade: 418

  add another (y/n)? y

Insira o ID: 5
Insira o nome: Sam Clemens
Insira o valor: 56.78
Insira a quantidade: 419

  add another (y/n)? y

Insira o ID: 6
Insira o nome: Mark Twain
Insira o valor: 67.89
Insira a quantidade: 420

  add another (y/n)? n

p[ 0]    1  John Brown             12.34   415
p[ 1]    2  Mary Brown             23.45   416
p[ 2]    3  Mickey Mouse           34.56   417
p[ 3]    4  Minnie Mouse           45.67   418
p[ 4]    5  Sam Clemens            56.78   419
p[ 5]    6  Mark Twain             67.89   420

所有数据都正确存储,如果需要,您可以添加1000多个条目。您还应该通过内存错误检查程序(如Linux上的valgrind)运行任何使用动态内存的程序,该程序可以告诉您是否不正确地使用了您不拥有的内存块的指针。
一个简短的测试,从一个文件中重定向输入,而不是重新输入,可以确认是否存在任何内存问题,使用内存检查器很简单,只要运行你的程序,例如。

$ valgrind ./bin/produtos < dat/produtos.txt
==12885== Memcheck, a memory error detector
==12885== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==12885== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==12885== Command: ./bin/produtos
==12885==

Insira o ID: Insira o nome: Insira o valor: Insira a quantidade:
  add another (y/n)?
Insira o ID: Insira o nome: Insira o valor: Insira a quantidade:
  add another (y/n)?
Insira o ID: Insira o nome: Insira o valor: Insira a quantidade:
  add another (y/n)?
Insira o ID: Insira o nome: Insira o valor: Insira a quantidade:
  add another (y/n)?
Insira o ID: Insira o nome: Insira o valor: Insira a quantidade:
  add another (y/n)?
Insira o ID: Insira o nome: Insira o valor: Insira a quantidade:
  add another (y/n)?
p[ 0]    1  John Brown             12.34   415
p[ 1]    2  Mary Brown             23.45   416
p[ 2]    3  Mickey Mouse           34.56   417
p[ 3]    4  Minnie Mouse           45.67   418
p[ 4]    5  Sam Clemens            56.78   419
p[ 5]    6  Mark Twain             67.89   420
==12885==
==12885== HEAP SUMMARY:
==12885==     in use at exit: 0 bytes in 0 blocks
==12885==   total heap usage: 3 allocs, 3 frees, 896 bytes allocated
==12885==
==12885== All heap blocks were freed -- no leaks are possible
==12885==
==12885== For counts of detected and suppressed errors, rerun with: -v
    ==12885== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)```

Always confirm `"All heap blocks were freed -- no leaks are possible"` and that there are no errors.

Look things over and let me know if you have further questions.
8yoxcaq7

8yoxcaq72#

p[i]struct produtos,而不是struct productos*。这意味着,要访问其成员,您需要使用.操作符,而不是->。即

printf("Insira o ID: ");
scanf("%d", &p[i].id);
printf("Insira o nome: ");
scanf("%s",  p[i].nm);
printf("Insira o valor: ");
scanf("%f", &p[i].vlrs);
printf("Insira a quantidade: ");
scanf("%d", &p[i].quant);

这与将p定义为main中的数组没有什么不同。当你把一个数组传递给一个函数时,它会衰减为指向它的第一个元素的指针。例如:

// This passes a pointer to the first element of an
// array of produtos to cadastroProdutos
struct produtos p1[5];
cadastroProdutos(p1, 5);
// This also passes a pointer to the first element
// of an array of produtos to cadastroProdutos
struct produtos* p2 = malloc(5 * sizeof(struct produtos));
cadastroProdutos(p2, 5);

cadastroProdutos函数的Angular 来看,这两个调用完全相同。在这两种情况下,它只接收指向数组第一个元素的指针和数组的大小。

u2nhd7ah

u2nhd7ah3#

运行这个。看看代码,你就会明白:

//
//  7.c
//  IFTM Exercises
//
//  Created by Lelre Ferreira on 8/29/19. Fix by Mr. J CHEN
//  Copyright © 2019 Lelre Ferreira. All rights reserved.
//

#define size 5
#include <stdio.h>
#include <stdlib.h>

struct produtos {

    int id;
    int quant;
    float vlrs;
    char nm[50];
};

void cadastroProdutos (struct produtos **p, int tamanho);
void maiorValorProdutos (struct produtos **p, int tamanho);
void maiorEstoqueProdutos (struct produtos **p, int tamanho);

int main (int argc, const char * argv[]) {

    struct produtos **p;
    int tamanho = 0, i;

    printf("Insira quantidade de produtos/itens a serem cadastrados: ");
    scanf("%d", &tamanho);
    p = (struct produtos **) malloc(tamanho   * sizeof(struct produtos*));
    for(i=0; i<tamanho; i++) {
        p[i] = (struct produtos *) malloc(tamanho   * sizeof(struct produtos));
    }
    cadastroProdutos(p, tamanho);
    maiorValorProdutos(p, tamanho);
    maiorEstoqueProdutos(p, tamanho);
    for(i=0; i<tamanho; i++) {
        free(p[i]);
    }
    free(p);
    return 0;
}

void cadastroProdutos(struct produtos **p, int tamanho) {

    int i = 0;
    for (i = 0; i < tamanho; i++) {

        printf("Insira o ID: ");
        scanf("%d", &(p[i]->id));
        printf("Insira o nome: ");
        scanf("%s",  p[i]->nm);
        printf("Insira o valor: ");
        scanf("%f", &(p[i]->vlrs));
        printf("Insira a quantidade: ");
        scanf("%d", &(p[i]->quant));
    }
}

void maiorValorProdutos(struct produtos **p, int tamanho) {

}

相关问题