gpt4 book ai didi

c - 如何动态分配结构+指针

转载 作者:行者123 更新时间:2023-11-30 16:14:16 25 4
gpt4 key购买 nike

我一直在尝试找出如何在结构数组中存储来自用户的信息,但是到目前为止……不起作用。

我创建了该结构,然后在主体内部创建了指向该结构的指针,然后动态分配了该结构。但是我真的不知道如何从用户那里获取信息。我知道,但是没有按预期工作。如果我只使用一个结构体数组,它将是这样的……

&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'的右值的地址...

最佳答案

您错过了理解,将[..]运算符应用于指针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作为指针传递,因此它的编号可以在函数中更新,并且 0失败时返回,而更新的 tamanho成功时返回,从而使您可以有意义地返回类型 size_t

避免在代码中使用幻数。您已经很好地为 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个分配的结构开始,然后继续输入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)


始终确认 "All heap blocks were freed -- no leaks are possible"并且没有错误。

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

关于c - 如何动态分配结构+指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57779644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com