C structure code compiling but not running - c

I learnt (self-learning) the basics of structure in C today and wrote this simple code. it is compiling without any error. I know that successful compilation is no guarantee for a bug-free software. While execution, it scans the inputs for two structure variables only and gives erroneous display. for the sake of simplicity I chose a char to store the book name. I am not able to figure out the bug here. could you find one?
#include<stdio.h>
int main(void)
{
struct book
{ char name;
float price;
int pages;
};
struct book b[3];
int i;
for (i = 0; i <= 2; i++){
printf("\nEnter name, price and pages ");
scanf("%c %f %i", &b[i].name, &b[i].price, &b[i].pages);
}
for (i = 0; i <= 2; i++)
printf("\n%c %f %i",b[i].name, b[i].price, b[i].pages);
return 0;
}

You need to remove "extra" input by adding while((ch=getchar())!='\n'); ( to flush the input buffer) (Please declare the char ch;):
for (i = 0; i <= 2; i++){
printf("\nEnter name, price and pages ");
scanf("%c %f %i",&b[i].name,&b[i].price, &b[i].pages);
while((ch=getchar())!='\n'); //eat the chars
}
Tutorial/posts:
"Flushing" the input stream
How to Get User Input from console -- safely.

Related

Code to print data of a name, price and its pages by using arrays

#include<stdio.h>
int main(){
char name[3];
float price[3];
int i,page[3];
printf("enter the name price and book\n");
for(i=0;i<3;i++){
scanf("%s",name[i]);
printf("enter character:\n");
}
for(i=0;i<3;i++) {
scanf("%f",&price[i]);
printf("enter floating point number:\n");
}
for(i=0;i<3;i++) {
scanf("%d",&page[i]);
printf("enter digit:\n");
}
printf("\n");
for(i=0;i<3;i++) {
printf("%s\n",name[i]);
}
for(i=0;i<3;i++) {
printf("%f\n",&price[3]);
}
for(i=0;i<3;i++){
printf("%d\n",&page[i]);
}
return 0;
}
When I was trying this code, I thought this was quite simple to do but I realized, there is something which I am missing in the code. The main problem with this code is it is not scanning the values of price and pages. I don't understand where I am mistaken.
So, please correct my code so that it will print the values of name price and pages.
There are a number of issues in your code. First and foremost, the %s specifier (for both the scanf and printf functions) expects a string argument (that is, a nul-terminated array of char for printf or an array sufficiently large to hold the input characters plus that terminator, for scanf); however, you are attempting to read (and print) a single char value in each of the relevant for loops.
To fix this, use the %c format specifier, instead of %s. However, when you use this, the newline character that is generated when you press the Enter key will be left in the input buffer, and that will be read as the actual char input on the next iteration of the first for loop. To clear any such newline (or, indeed other whitespace) from the input before the real input, add a space in the format string before the %c. Also, when using this, you will need to pass the address of each name element: scanf(" %c", &name[i]);.
Further, the printf function takes the actual values of the variables to be output, rather than their addresses – so remove the & from the arguments in your printf calls. (Also, and I assume it's a typo, the price[3] expression should be price[i] – the former attempts to access an out-of-bounds element of the price array.)
Another issue is that, in each of your input loops, you call the scanf function before you display the relevant prompt. In the code below, I have reversed your printf and scanf lines in each of those input loops.
Here's a possible fixed version:
#include<stdio.h>
int main()
{
char name[3];
float price[3];
int i, page[3];
printf("enter the name price and book\n");
for (i = 0; i < 3; i++) {
printf("enter character:\n");
scanf(" %c", &name[i]);
}
for (i = 0; i < 3; i++) {
printf("enter floating point number:\n");
scanf("%f", &price[i]);
}
for (i = 0; i < 3; i++) {
printf("enter digit:\n");
scanf("%d", &page[i]);
}
printf("\n");
for (i = 0; i < 3; i++) {
printf("%c\n", name[i]);
}
for (i = 0; i < 3; i++) {
printf("%f\n", price[i]);
}
for (i = 0; i < 3; i++) {
printf("%d\n", page[i]);
}
return 0;
}

Having problems with 2D char arrays

So I've got an assignment where my program asks the brand (10 letters), model (10 letters), age (1986 - 2019) and cost (positive real number) of 10 cars and then wants the program to check which car is the oldest and to print out it's brand and model. I don't have a problem with the first part but with the second part.
The code is:
//First part
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C 10
#define M 11
int main(void)
{
char brand[C][M];
char model[C][M];
int year[C];
float cost[C];
int i, len1, len2, min;
for(i=0; i<C; i++){
printf("Car %d\n", i+1);
do{
printf("Brand: ");
scanf("%s", brand[i]);
len1 = strlen(brand[i]);
} while(len1<0 || len1>10);
do{
printf("Model: ");
scanf("%s", model[i]);
len2 = strlen(model[i]);
} while(len2<0 || len2>10);
do{
printf("Year: ");
scanf("%d", &year[i]);
} while(year[i]<1986 || year[i]>2019);
do{
printf("Cost: ");
scanf("%d", &cost[i]);
} while(cost[i]<=0);
}
//Second part
year[0] = min;
for(i=0; i<10; i++)
if(year[i] < min){
min = year[i];
printf("\nThe oldest car is %s %s\n", brand[i], model[i]);
}
For some reason it either prints out gibberish in the place of brand[i] or if I lose the columns of the if statement prints out all the car brands and their models, where I only want the oldest one.
Aside from scanf not being recommended there are some problems with this code, first when you read the brand and model you do:
do{
printf("Brand: ");
scanf("%s", brand[i]);
len1 = strlen(brand[i]);
} while(len1<0 || len1>10);
The problem here is that you first write the string to brand[i] and then check if it's too long, but you have already written it into the array so if the string is longer than your space you already have a buffer overflow. Limit the size you can read with scanf using scanf("%10s, brand[i]) or better yet use fgets(brand[i], sizeof(brand[i]), stdin).
Next in the second part you use min without initializing it, and you overwrite the content of year[0] with it. You probably wanted something like:
min = 2020; // or a number that will be bigger than all your cars anyway
int older = 0;
i = 0;
for(i=0; i<C; i++){ // Use C here, you have it might as well use it instead of magic numbers
if(year[i] < min){
older = i;
min = year[i];
}
}
printf("\nThe oldest car is %s %s\n", brand[older], model[older]);
but bare in mind that this solution will print multiple cars if they are the oldest ones and have the same year

Extreme sum values calculated inside a structure

While I was learning to code in C about structure and pointers, I tried to make a program that calculate grades of students.
I thought it would work from my previous experiences for such calculation without pointers and structure. But with those, it gave me wild results in the program.
#include <stdio.h>
#include <string.h>
/*
The program will scan year, name, score of three different subjects,
and calculate the sum and the average.
Three different people (using array) will be taken into account.
*/
struct grade {
int year;
char name[20];
int score[3];
int total;
float avg;
};
void main() {
struct grade p[3];
char str = 'c';
char *pstr = NULL;
int i, j;
pstr = &str;
for (j = 0; j < 3; j++) {
printf("Year of Admission: ");
scanf("%d", &p[j].year);
printf("Name of the Student: ");
scanf("%s", pstr);
strcpy(p[j].name, pstr);
for (i = 0; i < 3; i++) {
printf("The score for Subject %d: ", i + 1);
scanf("%d", &p[j].score[i]);
p[j].total += p[j].score[i];
}
p[j].avg = p[j].total / 3.0;
}
for (j = 0; j < 3; j++) {
printf("%s's\n", p[j].name);
printf("Total score: %d\n", p[j].total);
printf("Average: %.2f\n", p[j].avg);
}
}
I could have written each of three different subjects as one variable but for an extra "challenge", I made an array inside the structure.
int score[3];
However, the program only prints out extremely small number -89541694... for both totals and averages.
I assume that this particular line inside a for-loop is a problem.
scanf("%d", &p[j].score[i]);
But I could not figure out why. I am really new to pointers and still learning them.
I hope for your generous teaching and explanations.
Thank you in advance.
Local variables are not initialized with 0, so you just need to zero it before calculating total:
p[j].total = 0;
before
for (i = 0; i < 3; i++) {
printf("The score for Subject %d: ", i + 1);
scanf("%d", &p[j].score[i]);
p[j].total += p[j].score[i];
}
The variable pstr points to a single char. A string in C needs to be at least two characters for a single-character string: The actual character, and the null terminator.
When you use e.g. scanf to read a string, the function will write at least two bytes to the memory pointed to by pstr. But since it only points to a single byte you will write out of bounds and that leads to undefined behavior.
If you want to be able to read more than a single character you need to have more space allocated for the string. And you need to limit scanf so it will not write out of bounds.
For example
char pstr[40]; // Allows for strings up to 39 character, plus terminator
// ...
scanf("%39s", pstr); // Read at most 39 characters from standard input, and write to pstr
Another problem is that local variables are not automatically initialized, their values will be indeterminate.
That means the contents of the array p is unknown and seemingly random.
When you do
p[j].total += p[j].score[i];
you use the seemingly random value of p[j].total to calculate another seemingly random number.
To initialize all structures and all their members to "zero" in the array, do e.g.
struct grad p[3] = { 0 };
Instead of making pstr a pointer you might wanted to do somehting like this
char pstr[30];
And accordingly you will scanf the string using scanf("%29s",pstr); and check it's return value.
To describe the problem a bit - you had a pointer pointing to a char which is not capable of holding an input characters and the corresponding \0 (nul terminating character). As a result this gives rise to undefined behavior. And then using it in strcpy is also an illegal code. (Undefined behavior).
Here the solution I gave simply declared an array of 30 characters and we limited the string input using scanf upto 29 characters because we need to store the terminating null.
Showing you atleast a bit of code to make you understand how to write these codes:-
if( scanf("%29s",pstr)!= 1){
fprintf(stderrm"Error in input");
exit(EXIT_FAILURE);
}
Another problem is initialize the variables - here you used p[j].total += p[j].score[i]; What is the value of p[j].total initially. It contains garbage value. In the loop make p[j].total = 0; first. That will give you the correct result.
Note: The wild results are the garbage value resulted from addition of some garbage value with p[j].score[i].
Also note that without making the changes that I said if you only change the initialization thing then also code is not guranteed to work. undefined behavior is undefined behavior - cases may arise which will simply crash the program making you wonder where you went wrong.
Illustration code may help you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
The program will scan year, name, score of three different subjects,
and calculate the sum and the average.
Three different people (using array) will be taken into account.
*/
struct grade {
int year;
char name[20];
int score[3];
int total;
float avg;
};
int main(void) {
struct grade p[3];
char pstr[20];
int i, j;
for (j = 0; j < 3; j++) {
printf("Year of Admission: ");
if(scanf("%d", &p[j].year)!=1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
printf("Name of the Student: ");
if(scanf("%19s", pstr)!=1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
strcpy(p[j].name, pstr);
p[j].total = 0;
for (i = 0; i < 3; i++) {
printf("The score for Subject %d: ", i + 1);
if(scanf("%d", &p[j].score[i])!=1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
if(p[j].score < 0){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
p[j].total += p[j].score[i];
}
p[j].avg = p[j].total / 3.0;
}
for (j = 0; j < 3; j++) {
printf("%s's\n", p[j].name);
printf("Total score: %d\n", p[j].total);
printf("Average: %.2f\n", p[j].avg);
}
return 0;
}
In fact instead of using the pstr just input the names directly in the structure variable instance itself. No need to use a temporary variable.

Strange error while adding a feature to my little game (0xC0000005)

Hello everyone,
I decided some time ago to write my own version of Minesweepers as some practice and I did it. The game ran perfectly, but after deciding to add a "Choose difficulty" option the window freezes and I get an error message, saying that the program does not respond. Also the line 0xC0000005 appeares. I have tryed many, many things: moving code from main() to a seperate function(now all in int playGame()), allocating some more memory in the heap, even creating a seperate .c file to store some piece of the code, but nothing worked sofar. I came back to the code after a few weeks, but I still have no clue why it is happening.
Can anyone help me with this? I hope my code is not hard to read. I added some comments explaining what is what. I am still new to C.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "difLvl.c"
int displayFiled(char **field); //prints out the map of the field
int combine(char answer, int answer1); //combines user input and field numeration
int Randomizer(int **mineArray); //generates random mine map
int difficulty();
int playGame();
int main(){
int playGame();
playGame();
system("PAUSE");
return 0;
}
int Randomizer(int **mineArray){
int difficulty();
int i, j;
srand(time(NULL));
int mines;
int placeMine;
int totalMines;
//int difLvl=2;
int difLvl=difficulty();
for(i=0, totalMines=0; i<10; i++){
for(j=0, mines=0; j<10 && mines<difLvl; j++){
placeMine= rand() % 2;
mineArray[i][j] = placeMine;
if(placeMine==1){
++mines;
};
};
totalMines+=mines;
};
return totalMines;
}
int displayFiled(char **field){
int i, j;
printf(" A B C D E F G H I J\n");
printf(" --------------------\n");
for (i=0; i<10; i++){
if (i==9){
printf("%d |", i+1);
}else{
printf("%d |", i+1);
};
for (j=0; j<10; j++){
printf("%c ", field[i][j]);
if (j==9){
printf("\n");
};
};
};
printf("\n");
return 0;
}
int playGame(){
int displayFiled(char **field);
int combine(char answer, int answer1);
int Randomizer(int ** mineArray);
char Y_char; //column as character (a, b, c etc.)
int X; //row
int Y; //Y_char converted to a number
int **mineArray; //stores the map of mines
char **fieldDisplay; //prints out the map of the field
int i, j; //counters
int life=1;
int movePl=0; //no dying on the first move
int globalMines; //number of mines placed
int openedFields=0; //counts the number of fields opened
//int difLvl;
//int difficulty();
//difLvl= difficulty();
/*disabled the trhee lines above while I was trying some solutions*/
/*int difficulty() is now called from int Randomizer()*/
system("cls");
/*Allocates memory to mineArray*/
mineArray= (int*)calloc(10, sizeof(int));
for(i = 0; i < 10; i++){
mineArray[i] = calloc(10, sizeof(int));
};
/*Allocates memory to fieldDisplay*/
fieldDisplay= (int*)calloc(10, sizeof(int));
for(i = 0; i < 10; i++){
fieldDisplay[i] = calloc(10, sizeof(int));
};
/*default look of fields with ?*/
for (i=0; i<10; i++){
for (j=0; j<10; j++){
fieldDisplay[i][j]='?';
};
};
globalMines= Randomizer(mineArray);
while(life==1 && openedFields<(100-globalMines)){
/*for checking purposes only*/
/*for (i=0; i<10; i++){
for (j=0; j<10; j++){
printf("%d ", mineArray[i][j]);
if (j==9){
printf("\n");
};
};
};*/
//printf("\nDifficulty level %d\n", difLvl);
printf("Total number of mines is %d\n\n", globalMines);
printf("\tMove nr. %d\n\n", movePl+1);
displayFiled(fieldDisplay);
printf("Which field do You want to activate?\nType first the letter, space and then the number (A 1, B 10 etc.)\n");
scanf("%c %d", &Y_char, &X);
if (Y_char >= 'A' && Y_char <= 'Z'){
Y = Y_char - 'A';
}else if(Y_char >= 'a' && Y_char <= 'z'){
Y = Y_char - 'a';
};
/*checks if a field is a mine*/
/*X-1 because the player chooses from 1 to 10*/
if (mineArray[X-1][Y]==0 && fieldDisplay[X-1][Y]=='?'){
movePl++;
fieldDisplay[X-1][Y]='0';
openedFields=openedFields+1;
OPEN : if (((X-2)<10) && ((X-2)>=0)){
if (mineArray[X-2][Y]==0 && fieldDisplay[X-2][Y]=='?'){
fieldDisplay[X-2][Y]='0';
openedFields=openedFields+1;
};
};
if ((X<10) && (X>=0)){
if (mineArray[X][Y]==0 && fieldDisplay[X][Y]=='?'){
fieldDisplay[X][Y]='0';
openedFields=openedFields+1;
};
};
if (((Y+1)<10) && ((Y+1)>=0)){
if (mineArray[X-1][Y+1]==0 && fieldDisplay[X-1][Y+1]=='?'){
fieldDisplay[X-1][Y+1]='0';
openedFields=openedFields+1;
};
};
if (((Y-1)<10) && ((Y-1)>=0)){
if (mineArray[X-1][Y-1]==0 && fieldDisplay[X-1][Y-1]=='?'){
fieldDisplay[X-1][Y-1]='0';
openedFields=openedFields+1;
};
};
system("cls"); //clears console screen
}else if (mineArray[X-1][Y]==0 && fieldDisplay[X-1][Y]=='0'){
system("cls");
printf("You can't choose an already opened field!\n\n");
}else if(mineArray[X-1][Y]==1 && movePl==0){
/*only activates on the first turn if players hits mine*/
movePl++;
mineArray[X-1][Y]= 0;
fieldDisplay[X-1][Y]='0';
globalMines=globalMines-1;
goto OPEN;
system("cls");
}else{
system("cls");
printf("YOU DIED ! YOU DIED ! YOU DIED !\n\n");
printf("Moves successfully made: %d\n\n", movePl-1);
fieldDisplay[X-1][Y]='1';
displayFiled(fieldDisplay);
--life;
};
};
if(openedFields==(100-globalMines)){
printf("Congratulations! You won the game!\n\n");
displayFiled(fieldDisplay);
};
for(i = 0; i < 10; i++){
free(mineArray[i]);
};
free(mineArray);
for(i = 0; i < 10; i++){
free(fieldDisplay[i]);
};
free(fieldDisplay);
return 0;
}
The difLvl.c file:
#include <stdio.h>
#include <stdlib.h>
int difficulty(){
int difLvl;
while(1){
printf("Please choose a difficulty level:\n");
printf("Easy-1\nNormal-2\nNightmare-3\n");
printf("Your answer: ");
scanf(" %d", &difLvl);
if(difLvl>=1 && difLvl<=3){
break;
}else{
system("cls");
continue;
};
};
system("cls");
return difLvl;
}
I created it, because I thought that maybe main() had too many code in it and that maybe that was why the difficulty option wasnt working right.
EDIT
After the user is promped to enter the difficulty level, the mine map is created, but after choosing a filed, the program crashes.
SOLVED
scanf("%c %d", &Y_char, &X);
changed to
scanf(" %c %d", &Y_char, &X);
First, you don't allocate your two-dimensional fields correctly. The "outer" field must hold int *, not just int:
mineArray = calloc(10, sizeof(*mineArray));
for (i = 0; i < 10; i++) {
mineArray[i] = calloc(10, sizeof(*mineArray[i]));
}
Another potential source of the segmentation fault is that Y might end up uninitialised and therefore with a garbage value. The cause is the scanf:
scanf("%c %d", &Y_char, &X);
Most scanf formats skip white space before the conversion, but %c doesn't. It is very likely that you read the newline character as the char for %c when you expect to read a letter. Because the new-line character is white space, you can hot-fix the by placing a space before the %c? format:
scanf(" %c %d", &Y_char, &X);
(I say hot-fix, because it isn't a good solution. scanf doesn't treat new-line characters specially; they are just space. A better solution might be to read a line first with fgets and then scan that with sscanf. At least you can treat each line as frash input. (And your input really should ensure that bad input is ignored.)
Lastly, it is strange that you include a *.c file. If you want to spread ypur project over various files, which is basically a good idea, you should write a header file for each *.c, which has the file's interface. Include the header files in other *.c files; compile the *.c files into objects separately and then link them. This process is usually controlled by Makefiles or Projects.

I can't type all the information in an array of structs

When I try to compile this small program everything is correct but when I run it I find some problems. For example, I can't type the "c" variable in the second element of the table and so on.
#include <stdio.h>
struct point{
char c;
int x,y;
};
int main(void)
{
int size = 4;
struct point tp[size];
for(int i = 0; i < size; i++ )
{
printf("entrer le nom du point no %d: ", i+1);
tp[i].c = fgetc(stdin);
printf("x = ");
scanf("%d", &tp[i].x);
printf("y = ");
scanf("%d", &tp[i].y);
}
}
There are a lots of similar questions here, for example: C scanf() and fgets() problem, fgets doesn't work after scanf.
You could use fgets() for user input and parse string with sscanf() for example.
Or you can use fgetc(stdin); after each scanf() to get rid of '\n' symbol.

Resources