如何动态分配结构+指针

时间:2019-09-03 23:07:08

标签: c arrays pointers 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'的右值的地址...

3 个答案:

答案 0 :(得分:0)

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函数的角度来看,这两个调用是完全相同的。在这两种情况下,它只接收一个指向数组第一个元素和数组大小的指针。

答案 1 :(得分:0)

您错过了理解,将[..]运算符应用于指针p(例如p[0])充当了对类型struct produtos'.'的引用适当的运算符(而不是@MilesBudnek's答案中指出的struct produtos*

除了'.''->'运算符问题之外,您似乎还缺少动态分配的要点。虽然可以从#define size 5分配的结构开始,但动态分配内存的目的是能够根据需要重新分配额外的内存来处理所有输入(或直到运行),从而无缝地处理第6个结构可用内存不足。)

当前编写函数cadastroProdutos的方式并不能真正实现干净的动态分配(除了它返回void且其中没有任何输入有效的事实之外) )。与其在函数中循环size次,您仅希望每次调用cadastroProdutos时都获得1个结构的数据。这样,您可以根据需要多次调用它,直到输入所有数据为止。不需要在函数内循环,并且scanf的使用非常脆弱,因为由于匹配失败或只是偶然输入的流浪字符(例如,为stdin输入的'a'或长度超过id个字符的名称,等等)

要解决大多数问题,请不要对用户输入使用49,而应将所有用户输入读入大小合适的临时缓冲区(例如scanf个字符),并且然后使用1024从缓冲区解析所需的信息。这具有双重好处,即可以分别验证读取和解析。并通过使用合理大小的缓冲区,每次都消耗一整行输入,从而消除了多余的字符问题(例如,踩在键盘上的猫)。

您的sscanf接受输入,没有提供有意义的返回值来指示输入成功/失败,如果任何一个输入失败,则函数容易受到未定义行为的影响。因此,通过检查所用功能的返回来验证每个用户输入。在任何输入失败中,为失败返回cadastroProdutos,并且在成功上返回非零,则可以在调用函数中处理所有输入失败。

注意:计数类型应使用0而不是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,而更新后的{{1 }}成功返回,使您可以有意义地返回类型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 */ } 提示,以确定用户是否要添加更多数据)

使用/输出示例

上面,我们从2个分配的结构开始,然后继续输入6个结构,强制进行重新分配。一个例子可能是:

#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 */
}

所有数据都已正确存储,如果需要,您可以添加1000个以上的条目。您还应该通过内存错误检查程序(例如Linux上的add another (y/n)?)运行任何使用动态内存的程序,该程序可以判断您是否滥用了您不拥有的内存块指针。

简短的重定向文件输入而不是重新键入的测试可以确认是否存在任何内存问题,并且使用内存检查器非常简单,只需运行程序即可,例如

$ ./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

始终确认valgrind并且没有错误。

仔细检查一下,如果还有其他问题,请告诉我。

答案 2 :(得分:0)

运行此代码,查看您将了解的代码

//
//  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){



}