I think the root of the problem is your addvara function, your loops don't make sense.
With i=length; you are overwriting the running index, then you do
length++;. If the user wishes to continue, you exit the for loop and enter it
again, depending on the number of times the user inputs the values, you are
going to eventually access varor out of bounds, which is undefined behaviour
and a segfault is a consequence of that.
I'd rewrite the addvara function like this:
// helper function to clean stdin
void clean_stdin()
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
// helper function to read in a loop until you get the value
// return 1 on success, 0 on failure, cannot continue reading
int read_from_stdin(const char *format, void *ptr, const char *prompt)
{
int err;
do {
if(prompt)
{
printf("%s", prompt);
fflush(stdout);
}
err = scanf(format, ptr);
if(err == EOF)
return 0;
if(err != 1)
{
printf("Invalid value, try again\n");
clean_stdin();
}
} while(err != 1);
return 1;
}
int addvara(struct vara varor[], int length)
{
if(varor == NULL)
return -1; // error value
if(length < 0)
return -1;
// helper to creata a format for scanf
// %29[^\n]s, the number depends on sizeof varor[0].namn
char strfmt[100];
sprintf(strfmt, "%%%zu[^\n]s", sizeof(varor[0].namn) - 1);
int i;
for(i = 0; i < length; ++i)
{
int ask;
if(read_from_stdin("%d", &ask, "Vill du scanna in vara? 1 för ja. 0 för att återgå till menyn\n") == 0)
{
fprintf(stderr, "cannot continue reading\n");
return i; // number of values added so far
}
if(ask == 0)
return i; // the number of values added
// otherwise scanf might complain about leftovers in the input buffer
clean_stdin();
if(read_from_stdin(strfmt, varor[i].namn, "Namm: ") == 0)
{
fprintf(stderr, "cannot continue reading\n");
return i; // number of values added so far
}
// otherwise scanf might complain about leftovers in the input buffer
clean_stdin();
if(read_from_stdin("%d", &varor[i].saldo, "Saldo: ") == 0)
{
fprintf(stderr, "cannot continue reading\n");
return i; // number of values added so far
}
if(read_from_stdin("%d", &varor[i].nummer, "Varunummer: ") == 0)
{
fprintf(stderr, "cannot continue reading\n");
return i; // number of values added so far
}
putchar('\n');
}
return i;
}
Your printing function looks OK. But you could improve how your format your
output, for example:
void view(struct vara varor[], int length)
{
printf("%-30s %-10s %s\n", "Namn", "Saldo", "Nummer");
for(int i=0; i<length; i++)
printf("%-30s %-10d %d\n", varor[i].namn, varor[i].saldo, varor[i].nummer);
}
The output would look like this
Namn Saldo Nummer
Jan 129 1113232
Maria 232 44342234
edit
As chux pointed out in the comments, my read_from_stdin function has technically
undefined bevahiour, because scanf expects a int* pointer for the %d
format and I'm using a void* pointer.
I'd like to quote chux here:
chux wrote in the comments
"%d" expects a int *, not a void *. A void * and int* could be of different widths, encodings
However after 15 year of writing C code, I've never come across a commonly used architecture where this is the case and
a function like this would actually fail. Unless your target architecture isn't an exotic one, this function would work as I intended.
i=length;within the body offor(int i=0; i<length; i++)makes no sense. You then incrementlengthso that's an infinite loop? Please post the Minimal, Complete, and Verifiable example that shows the problem.addvarais confusing, how do you incrementlength? You are most probably indexing the array out of bound which is undefined behaviour and a segaullt is the consequence.scanf(). example:scanf("%s", varor[i].namn);-->if (scanf("%29s", varor[i].namn) != 1) Handle_Error();. Like wise for the otherscanf().