I've been trying to find out how to store information from the user in an array of struct, but so far... Not working.
I created the struct, and inside the main I created the pointer to that struct, then I dynamically allocated that struct. But I don't really know how I'm going to get the info from the user, I mean. I know it but it's not working as expected. If I was using only an array of struct, it would be something like this...
&p[i].id //Normal
I tried to use this method but not working, idk why... The code is not completed yet...
//
// 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){
}
The IDE is giving this error: Cannot take the address of an rvalue of type 'int'...
p[i]
is a struct produtos
, not a struct productos*
. That means, to access its members you use the .
operator, not ->
. ie
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);
This is no different than it would be had you defined p
as an array in main
. When you pass an array to a function it decays to a pointer to its first element. For example:
// 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);
From the perspective of the cadastroProdutos
function, those two calls are exactly the same. In both cases, it just receives a pointer to the first element of an array and the size of the array.
You missed understanding that the [..]
operator applied to your pointer p
(eg p[0]
) acts as a dereference making the type struct produtos
and the '.'
operator proper (instead of struct produtos*
as noted in @MilesBudnek's answer.
Aside from your '.'
or '->'
operator problem, you seem to be missing the point on dynamically allocating. While it is fine to start with #define size 5
allocated structs, the point of dynamically allocating memory is being able to handle your 6th struct seamlessly by reallocating additional memory on as as-needed basis to handle all your input (or until your run out of available memory).
The way you currently have your function cadastroProdutos
written, doesn't really make a clean dynamic allocation possible (in addition to the fact it returns void
and there is no validation of any input within it). Rather than looping size
times within your function, you simply want to get 1-struct worth of data each time cadastroProdutos
is called. That way you can call it as many times as needed until all your data is entered. There is no need to loop within your function, and your use of scanf
is horribly fragile as you have no way to handle characters left in stdin
due to a matching failure or simply stray characters accidentally typed, (eg 'a'
typed for id
, or a name longer than 49
characters, etc.)
To resolve a majority of the problems, don't use scanf
for User-Input, instead read all User-Input into a temporary buffer of reasonable size (eg 1024
characters or so) and then parse the needed information from the buffer using sscanf
. This has the double-benefit of allowing separate validation of both the read and parse; and by using a reasonable sized buffer you eliminate the extraneous character problem (such as a cat stepping on the keyboard) by consuming a complete line of input every time.
Your cadastroProdutos
which takes input, provides no meaningful return to indicate success/failure of the input leaving your function susceptible to Undefined Behavior if any one input fails. So validate EVERY user input by checking the return of the function(s) used. Of any input failure, returning 0
for failure , and non-zero on success allows you to handle any input failure back in the calling function.
( note: counting types should use size_t
instead of int
)
Putting those changes together for your cadastroProdutos
, you could do something similar to:
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) */
}
( note: tamanho
is passed as a pointer so its number can be updated within the function, and 0
is returned on failure, while the updated tamanho
is returned on success allowing you a meaningful return of type size_t
)
Avoid using magic-numbers in your code. You did a good job defining a constant for size
, now just fining defining the constants you need so there are no more magic-numbers like char nm[50];
with it. Doing that you could use a couple more #define
, eg
#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;
Now all you need to do in main()
is to declare a temporary buffer to hold the line, and size_t
values, the total number of struct currently allocated ( allocated
) and the number filled ( tomanho
) which leads to a simple check at the start of each loop if (tomanho == allocated)
, you know you need to realloc
additional struct before attempting to fill any more. Your main()
function can essentially be:
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;
}
}
At this point all your struct are filled and stored in p
and all you need to do is whatever you need to do with your data (simply output below) and then free()
the memory your have allocated, eg
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 */
}
Putting it altogether in a short example, you could do:
#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 */
}
( note: a simple add another (y/n)?
prompt is added to determine if the user wants to add more data)
Example Use/Output
Above we start with 2-allocated struct, and then proceed to enter 6 struct, forcing a reallocation to take place. An example could be:
$ ./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
All data is properly stored, and you could have added 1000 more entries if you desired. You should also run any program that uses dynamic memory through a memory error checking program (like valgrind
on Linux) that can tell if you have made improper use of a pointer of block of memory you don't own.
A short test redirecting the inputs from a file rather than retyping can confirm whether any memory problems exists, and using the memory checker is simple, just run your program though it, eg
$ 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.
Run this,See the code you will understand
//
// 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){
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.