Making my functions crash proof gives Segmentation fault: 11 - c

I am making a program that saves information about vehicles in an array made of structs and then prints it to a file. Included in the program are options to add and delete vehicles as well as printing out the saved vehicles and deleting vehicles. When choosing a vehicle to delete or print out I have to make sure the input from the user is an integer to prevent it from crashing, and if it is not an integer to give a custom error message and give the user another chance at the input. I have tried a couple of different approaches and the latest seemed promising but when running these functions I get "Segmentation fault: 11" regardless of if I input an integer or a character.
The functions seem to work just fine without the lines of code that are supposed to prevent crashing. Could someone please tell me what is causing the error or possible fixes to the problem. Thanks!
These are the functions that are causing the problem:
Function to remove vehicle:
This function takes in the array of structs as well as the int counter which counts the number of occupied spots in the array. The function then takes input from the user in the form of an int to choose which position to delete. The position can't be greater than counter or smaller than 0.
//Ta bort ett fordon
void del(int counter, fordon_t reg[])
{
int pos;
int i;
do{
printf("Vilken position ska tas bort?:");
char *tmp;
scanf("%s", tmp);
pos = atoi(tmp);
if (pos == 0)
{
printf("Var god och skriv en siffra\n");
}
}
while(pos == 0);
if(pos<0 || pos>=counter)
{
printf("Ogiltig position\n");
}
else
{
for(i=pos+1; i<counter; i++)
{
reg[i-1]=reg[i];
}
counter--;
for(i=0; i<counter; i++)
{
printf("%s %d %s %s %s\n", reg[i].owner.name, reg[i].owner.age, reg[i].type, reg[i].brand, reg[i].regnum);
}
}
}
Function to print out chosen vehicle:
This function works in the same way as the previous function but instead of deleting the chosen position it prints out the information on that position.
//Skriv ut specifikt fordon
void print_out(int counter, fordon_t reg[])
{
int val;
do
{
char *tmp;
printf("Vilken postition vill du se?:");
scanf("%s", tmp);
val = atoi(tmp);
if (val == 0)
{
printf("Var god och skriv en siffra\n");
}
}
while(val == 0);
if(val<0 || val>=counter)
{
printf("Ogiltig position\n");
}
else
{
printf("%s %d %s %s %s\n", reg[val].owner.name, reg[val].owner.age, reg[val].type, reg[val].brand, reg[val].regnum);
}
}
If additional information about my program is needed to solve the program please tell me and I will provide more of the code.

Related

Can't get while loop to work 2 times? (C)

So I'm trying to loop the name asking section as well as the age one, the age one worked fine but when I tried to do it with name one it doesn't work. What I'm just trying to achieve is that when you put a number in the name section or vice versa, you get an error message and it loops you back to the same question
#include <stdio.h>
int vek;
char name[20];
int result1;
int result2;
int main()
{
FindName();
void FindName() { // it wants me to put a ";" which doesn't make sense to me and doesn't work
printf("Napis svoje meno \n");
result2 = scanf("%s",&name);
while (gethar() != '\n');
if(result2 == 1){
printf("Ahoj %s \n",name);
break;
system("pause");
}
else {
printf("nepis sem cisla ty kokot \n");
}
findAge();
}
void findAge() {
printf("Napis svoj vek \n");
result1 = scanf("%d",&vek);
while (getchar() != '\n');
if(result1 == 1){
printf("%s si krasny %d rocny priklad downoveho syndromu \n ",&name,vek);
}
else {
printf("co si jebnuty \n");
findAge();
}
}
I've tried to just break the loop if it's the right answer but that wouldn't work either, I'm just a beginner
The while loop will run everything inside the body as long as the condition is true. You need to put the code that needs to be repeated in a block, between { and }. You've put a semicolon behind it. That means a null statement, or do nothing. That way the condition is checked until it is no longer true, but nothing else is done. For example:
int i=0;
while(i < 3) {
printf("%d\n", i);
i++;
}
That will print the numbers 0,1 and 2. And then it stops because the condition is no longer true.
You want the program to look like this. In pseudocode:
main:
call findName
call findAge
findName:
print "Something Eastern European asking for a name"
result = 0;
while result != 1:
result = read input
if result == 0
print "Try again"
And the same for findAge
Notice the functions never call themselves. They just run the loop until the input is valid.

Scanf within a loop is being skipped

I'm trying to ensure that the user has definitely entered an integer. However no matter what I type in, it doesn't seem to work.
Sometimes the scanf is completely ignored and the loop just prints out everything loads of times.
When I checked what the input was that the code took in, it was wrong as well.
Any ideas or help would be appreciated!
while (square_size == -1) {
square_size = get_input_size();
}
int get_input_size(void) {
int size;
printf("What size word square would you like to create? ");
scanf("%d", &size);
if (isdigit(size)) {
printf("VALID %d\n", size);
return size;
}
printf("ERROR: invalid input\n");
return -1;
}

Weird characters saved in my text file

I'm trying to make a program that can store certain information in a text file. The problem I have though is that with the code I've written so far, the information stored is a bunch of weird symbols and characters. I've managed to kind of find out where it happens from but I can't seem to solve it. It seems like in my register_item function, both item number and balance get weird values for some reason. If anyone can see what mistake I've made, that would be appreciated.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 20
struct vara
{
int itemnumber[20];
char name[30];
int balance[20];
};
open_file(FILE *ange_filnamn, char filnamn[], struct vara varor[], int *antal_varor)
{
int mainmenu = 0;
while (mainmenu != 1 && mainmenu != 2)
{
printf("Do you want to open an existing file (1) or create a new one (2)?\n");
scanf("%d", &mainmenu);
//system("CLS");
if(mainmenu==1)
{
printf("Choose filename (ex. .txt).\n");
scanf("%s", filnamn);
ange_filnamn=fopen(filnamn, "r+");
while(!feof(ange_filnamn))
{
fread(&varor[*antal_varor], sizeof(struct vara), 1, ange_filnamn);
if(!feof(ange_filnamn))
{
*antal_varor=*antal_varor + 1;
}
}
printf("\nNumber of items: %d \n",*antal_varor);
fclose(ange_filnamn);
}
if(mainmenu==2)
{
printf("What name do you want for your new file?\n");
scanf("%s", filnamn);
ange_filnamn=fopen(filnamn, "w+");
printf("File is created!\n");
*antal_varor = 0;
fclose(ange_filnamn);
}
}
}
register_item(struct vara *varor, int *antal_varor)
{
printf("Item number:\n");
scanf("%d", varor[*antal_varor].itemnumber);
printf("Name:\n");
scanf("%s", varor[*antal_varor].name);
printf("Balance:\n");
scanf("%d", varor[*antal_varor].balance);
*antal_varor+=1;
}
print_item(struct vara varor[], int antal_varor)
{
int i;
for (i=0; i < antal_varor; i++)
{
printf("%d. Item number: %d Name: %s Balance: %d\n", i, varor[i].itemnumber, varor[i].name, varor[i].balance);
}
}
quit_program(char filnamn[], struct vara varor[], int *antal_varor)
{
FILE *fil;
//printf("%s", filnamn);
fil=fopen(filnamn, "w+");
fwrite(varor, sizeof(struct vara), *antal_varor, fil);
fclose(fil);
}
int main(void)
{
FILE *ange_filnamn;
struct vara varor[MAX];
int mainmenu, menu, antal_varor=0;
char filnamn[20], filen[30];
open_file(ange_filnamn,filnamn, varor, &antal_varor);
//Second menu
while(menu!=7)
{
printf("\n");
printf("1. Register new items to inventory.\n");
printf("2. Print all items from inventory.\n");
printf("3. Search for item.\n");
printf("4. Change inventory.\n");
printf("5. Sort inventory.\n");
printf("6. Deregister item from inventory.\n");
printf("7. Quit.\n");
scanf("%d", &menu);
if(menu==1)
{
register_item(varor, &antal_varor);
}
if (menu==2)
{
print_item(varor, antal_varor);
}
if (menu==3)
{
printf("test");
}
if (menu==4)
{
printf("test");
}
if (menu==5)
{
printf("test");
}
if(menu==6)
{
printf("test");
}
if (menu==7)
{
quit_program(filnamn, varor, &antal_varor);
}
}
}
You have an array of structures. The array contains antal_varor number of structures, and each structure contains members (elements) itemnumber, name, and balance.
Before we get started, a little side note: I think your structure definition has some bugs. Based on the way you're using it, I think you want
struct vara
{
int itemnumber;
char name[30];
int balance;
};
But your question was about writing the file out. When you call
fwrite(varor, sizeof(struct vara), *antal_varor, fil);
you are writing out the entire array, all at once, in "binary", which is why you can't read it. If you want to write it out in a more human-readable form, you can do something like this. Here I have an explicit loop over the elements of the array, and each time through the loop, I print out all the members of that element:
int i;
for(i = 0; i < *antal_varor; i++ {
fprintf(fil, "varor %d:\n", i);
fprintf(fil, " itemnumber: %d\n", varor[i].itemnumber);
fprintf(fil, " name: %s\n", varor[i].name);
fprintf(fil, " balance: %d\n", varor[i].balance);
}
So, first try that. You should find that the output file is perfectly readable.
Now, the problem is that since you wrote the file out in this nicer, more readable format, your code that reads the data back in, that used to use
fread(&varor[*antal_varor], sizeof(struct vara), 1, ange_filnamn);
is not going to work any more. But here is the sort of code you could use to read the new-format file back in. This code reads the file line by line with fgets, figuring out what each line is, and plugging data items one by one into the varor array to rebuild it.
char line[80];
int i = 0;
*antal_varor = 0;
while(fgets(line, sizeof(line), ange_filnamn) != NULL) {
if(strncmp(line, "varor ", 6) == 0) {
sscanf(line, "varor %d:", &i);
if(i >= MAX) {
fprintf(stderr, "warning: index in file too large\n");
i = 0;
continue;
}
if(i + 1 > *antal_varor) *antal_varor = i + 1;
} else if(strncmp(line, " itemnumber:", 12) == 0) {
sscanf(line, " itemnumber: %d", &varor[i].itemnumber);
} else if(strncmp(line, " name:", 6) == 0) {
sscanf(line, " name: %s", varor[i].name);
} else if(strncmp(line, " balance:", 9) == 0) {
sscanf(line, " balance: %d", &varor[i].balance);
} else {
fprintf(stderr, "warning: unrecognized line in file\n");
}
}
printf("\nNumber of items: %d \n",*antal_varor);
fclose(ange_filnamn);
I haven't tested this, so there may be some little mistakes in it, but it should give you the idea.
(Also there are better ways of writing this sort of thing, but they're a little more elaborate or require more infrastructure, so I've stuck to something very simple and understandable, although it's less than robust.)
The commenters on your question have it right.
- What is displayed with printf (and written to a file with fprintf) is ASCII representation of the numbers.
- What is stored in memory (and written with fwrite) is the actual "binary" value.
In C, an int variable always takes up the same number of bytes in memory, regardless of the value stored. That is why your sizeof() works consistently. Reading and writing can be consistently done.
(Note that not all C implementations use the same size int though. It is 4 bytes in the x86 Linux I'm using right now).
When displaying the ASCII representation, the number of ASCII digit characters required depends on the value. So, if reading values in that have been stored this way, you have to 'parse' the text and build up the integer value from the digits read, and in general will be a variable number of digits. (This is what scanf does.) Hence, reading and parsing ASCII could be considered more complicated than just reading in a value stored as binary int that is always the same size.
IMPORTANT: If you are going to read the file as binary, you should open it with the "b" attribute like this:
ange_filnamn=fopen(filnamn, "r+b");
Similary, to open for binary write:
fil=fopen(filnamn, "w+b");

What's the error in this code?(C - File Handling)

What I want to do is to write n(taken from user) elements to a file.Then read the elements again to an array and sort them and again write them in another file.
Finally open that file and display its contents.
But the code seems not to work, all syntax, grammar etc is checked what's the error??
#include<stdio.h>
struct data
{
int a,ar[100];
}e;
int main()
{ FILE *f1,*f2;
int i,j,n,t;
printf("\nEnter Array Size:");
scanf("%d",&n);
f1=fopen("Array.txt","w");
for(i=0;i<n;i++)
{ printf("\nEnter %d element:",i+1);
scanf("%d",&e.a);
fprintf(f1,"%d",e.a);
}
fflush(stdin);
fclose(f1);
rewind(f1);
i=0;
f1=fopen("Array.txt","r");
while((fscanf(f1,"%d",&e.ar[i++]))!=EOF)
{}
fclose(f1);
for(i=0;i<n;i++)
{ for(j=0;j<n-1;j++)
{ if(e.ar[j]>e.ar[j+1])
{ t=e.ar[j];
e.ar[j]=e.ar[j+1];
e.ar[j+1]=t;
}
}
}
f2=fopen("Sort.txt","w");
i=0;
while((fprintf(f2,"%d",e.ar[i]))!=EOF)
{ i++;}
fclose(f2);
f2=fopen("Sort.txt","r");
while((fscanf(f2,"%d",&e.a))!=EOF)
{ printf("%d ",e.a);
}
fclose(f2);
return 0;
}
So you want to know the error? I found a HUGE one.
As I was running your program, I have determined a segmentation fault occurs after this line:
f2=fopen("Sort.txt","w");
The major error here is that you opened a file for writing data to it, but you're making a rather confusing loop.
This is your code:
i=0;
while((fprintf(f2,"%d",e.ar[i]))!=EOF)
{ i++;}
In the state it is in, the value of i will exceed the upper bound value of your ar int array. You set the upper bound value to 100, but in the while loop, it will run endlessly until segmentation fault happens (when i goes past 100) because fprintf will never return an EOF (according to what the linux manual on fprintf claims).
What I would suggest instead is this:
for(i=0;i<n;i++){
fprintf(f2,"%d",e.ar[i]);
}
where n is the number of elements to finally print (as indicated by user at beginning of the program).

Reading one file, parsing, and writing another

Consider the file,
L,12/5/2008,Blacktown
C,Willy Wonker,10.00
C,Adolph Hitler,20.00
C,Attila the Hun,30.00
C,Idi Amin,40.00
C,Ghengis Khan,50.00
T,150.00
L,13/5/2008,Parramatta
C,Attila the Hun,100.10
C,Willy Wonker,200.20
C,Ghengis Khan,300.30
T,600.60
L,14/5/2008,Mount Druitt
C,Adolph Hitler,1000.00
T,2000.00
L,15/5/2008,Penrith
T,0.00
L,16/5/2008,Chatswood
C,Ghengis Khan,1.00
C,Idi Amin,10.00
C,Adolph Hitler,100.00
C,Attila the Hun,1000.00
T,1111.00
I need to write a program that opens the file Collections.txt, reads it and formats it in the given order, and writes it to another file called Reports.txt. I need to have the date, a tab, and then the name. Then a new line and the names, a tab, and the amount. Repeat until a T is detected; this signals we have no more collections for the above location. Then rinse and repeat for every location until it reaches the end of the file and a final total must be displayed.
Here is the code I have written,
/*
This program collects data and writes it to a specific file.*/
#include <stdio.h>
#include <stdlib.h>
void debt_calculator();
void main()
{
printf("This is a debt collection program:\n ");
debt_calculator();
scanf("%*c");
}
void debt_calculator()
{
char code;
int date [40];
char location [40];
char name [40];
float amount = 0;
float total = 0;
float grand_total;
int ctr = 0;
FILE * Collections;
Collections=fopen("C:\\Users\\Nick\\Documents\\Visual Studio 2010\\Projects\\Assignment2\\Assignment2\\Collections.txt","r");
if(Collections==NULL)
{
printf("file not open:\n");
exit(1);
}
FILE * Report;
if((Report=fopen("C:\\Users\\Nick\\Documents\\Visual Studio 2010\\Projects\\Assignment2\\Assignment2\\Report.txt","w"))==NULL)
{
printf("can not open file: \n");
exit(1);
}
fscanf(Collections,"%c,",&code);
while(code == 'L')
{
fscanf(Collections,"%[^,],%s%*c",date,location);
fprintf(Report,"Date: %s \t Location: %s \n\n",date, location);
fscanf(Collections,"%c,",&code);
}
for(code == 'C'; ctr < 5; ctr++)
{
fscanf(Collections,"%[^,], %f %*c",name, & amount);
if(amount == 0)
{
fprintf(Report,"### No Collections for %s \n", location);
fprintf(Report,"total: \t 0.00\n");
}
fprintf(Report,"\n Name: %s \t Amount: %.2f \n",name, amount);
fscanf(Collections,"%c,",&code);
}
code == 'T';
while(code == 'T')
{
fprintf(Report,"Hello");
fscanf(Collections,"%f",& amount);
total += amount;
grand_total += total;
fprintf(Report,"Total: \t %.2f \n",& total);
fprintf(Report,"Grand Total of all Collections is: $ %.2f", grand_total);
fscanf(Collections,"%c" , & code);
}
fclose(Collections);
fclose(Report);
}
When I run the above program it displays the printf() statement and when I hit enter and it exits. Than I open my report.txt file and find the date tab location new line and all the names and costs up until the T. Once it gets to the 'T' it stops, I cant get it to go into the last while loop, read the total and print it to the file than repeat by checking the code again. The code after the T is a L so it should go back into the first while loop and read than write the date and location but it does not. Any ideas what I'm doing wrong?
Also if there's any better way you think I should be doing this please let me know.
Have you tries stepping in the debugger and observing the variable state while doing so?
This line:
fprintf(Report,"Total: \t %.2f \n",& total);
is certainly incorrect, %f does not expect a pointer.
If the expectation is that code == 'T'; will force it to enter the loop, you are mistaken, code = 'T'; would work.
Similarly in this loop:
for(code == 'C'; ctr < 5; ctr++)
The initialising expression shpuld be code = 'C'
Try setting your compiler warning level to \W4 and \Wx (all warnings are errors), then the compiler may help you spot such errors.

Resources