[英]How to dynamically allocate an struct + pointer
我一直在嘗試找出如何在結構數組中存儲來自用戶的信息,但是到目前為止……不起作用。
我創建了該結構,並在主體內部創建了指向該結構的指針,然后動態分配了該結構。 但是我真的不知道如何從用戶那里獲取信息。 我知道,但是沒有按預期工作。 如果我只使用一個結構體數組,它將是這樣的……
&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[i]
是struct produtos
,而不是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
函數的角度來看,這兩個調用是完全相同的。 在這兩種情況下,它僅接收一個指向數組第一個元素和數組大小的指針。
您可能錯過了理解,應用於指針p
的[..]
運算符(例如p[0]
)充當了對struct produtos
和'.'
類型的引用'.'
適當的運算符(而不是@MilesBudnek的答案中指出的struct produtos*
。
除了您的'.'
或'->'
運算符問題,您似乎缺少動態分配的要點。 從#define size 5
分配#define size 5
結構開始是可以的,但動態分配內存的目的是能夠通過根據需要重新分配額外的內存來處理所有輸入(或直到用盡)來無縫處理第6個結構可用內存)。
當前編寫函數cadastroProdutos
的方式並不能真正實現干凈的動態分配(除了它返回void
並且其中沒有任何輸入經過驗證的事實)。 與其在函數中循環size
時間,不如只是在每次調用cadastroProdutos
獲取值1結構的數據。 這樣,您可以根據需要多次調用它,直到輸入所有數據為止。 無需在函數內循環,並且對scanf
的使用非常脆弱,因為您將無法處理由於匹配失敗而導致的stdin
遺留的字符,或者只是偶然輸入了雜散字符(例如,為id
鍵入的'a'
,或名稱超過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];
這樣的幻數了 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)?
了一個簡單的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"
,並且沒有錯誤。
仔細檢查一下,如果您還有其他問題,請告訴我。
運行它,查看您將了解的代碼
//
// 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){
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.