Trying to make a program that prints data entered into a file.
Everything is working all and good apart from the Calculating Average for marks entered.
I can't seem to figure out how to do it, even though it should be simple I just cant get my head around it.
The error I am currently getting is:
"temp->mark = temp->mark + studentArray[j];" (Invlalid operands to
binary + (have 'float' and 'char *').
Much appreciated if someone could help me. I have tried the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
struct student{
char name[30];
int id;
float mark;
};
int count = 0;
void student_update(char *stuadd);
void display(char *stuadd);
void main(int argc, char *studentArray[100])
{
int choice;
while(1)
{
printf("Welcome to Student Archives\n\n");
printf("1. Display Students' Details\n");
printf("2. Calculate average of all students’ marks \n");
printf("3. Add new student to the record \n");
printf("4. Quit Program\n");
scanf("%d",&choice);
switch(choice)
{
case 1:display(studentArray[100]);
break;
case 2:
break;
case 3:
student_update(studentArray[100]);
break;
case 4: printf("Program Terminated.\n");
exit(0);
default: printf("Wrong Choice. Enter again\n");
break;
}
}
}
void display(char *stuadd)
{
FILE *fptr;
char ch;
int rec = count;
fptr = fopen("stuadd.txt", "r");
struct student *temp = (struct student *)malloc(sizeof(struct student));
if (fptr == NULL)
printf("File does not exist.");
else
{
while (rec)
{
fread(temp->name, 50, 1, fptr);
printf(" %s\n", temp->name);
fread(&temp->id, sizeof(int), 1, fptr);
printf("%d", temp->id);
fread(&temp->mark, sizeof(int), 1, fptr);
printf("%.2f", temp->mark);
rec--;
}
}
fclose(fptr);
free(temp);
free(temp->name);
}
void calculateAverage(char *studentArray[100])
{
struct student *temp = (struct student *)malloc(sizeof(struct student));
int j;
float avg;
temp->mark = avg = 0;
for(j = 0; j < 100; j++)
{
temp->mark = temp->mark + studentArray[j];
}
avg = (float)temp->mark / j;
printf("Average of students' total marks are: %.2f",avg);
}
void student_update(char *stuadd)
{
FILE *fptr;
fptr = fopen("stuadd.txt", "a+");
struct student *temp = (struct student *)malloc(sizeof(struct student));
if (fptr == NULL)
printf("\nError.");
else
{
printf("\nEnter the students' name\n");
scanf(" %[^\n]s", temp->name);
printf("Enter the students' ID\n");
scanf("%d", &temp->id);
printf("Enter the students' mark\n");
scanf("%f", &temp->mark);
fprintf(fptr, "%s %d %.2f", temp->name, temp->id, temp->mark);
count++;
}
fclose(fptr);
free(temp);
free(temp->name);
}
The posted code does not compile!
under ubuntu linux, using:
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" (in directory: /home/richard/Documents/forum)
the compiler outputs the following:
untitled.c:16:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main(int argc, char *studentArray[100])
^~~~
untitled.c: In function ‘main’:
untitled.c:16:15: warning: unused parameter ‘argc’ [-Wunused-parameter]
void main(int argc, char *studentArray[100])
^~~~
untitled.c: In function ‘display’:
untitled.c:48:10: warning: unused variable ‘ch’ [-Wunused-variable]
char ch;
^~
untitled.c:45:20: warning: unused parameter ‘stuadd’ [-Wunused-parameter]
void display(char *stuadd)
^~~~~~
untitled.c: In function ‘calculateAverage’:
untitled.c:83:33: error: invalid operands to binary + (have ‘float’ and ‘char *’)
temp->mark = temp->mark + studentArray[j];
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
untitled.c:86:29: warning: conversion to ‘float’ from ‘int’ may alter its value [-Wconversion]
avg = (float)temp->mark / j;
^
untitled.c: In function ‘student_update’:
untitled.c:91:27: warning: unused parameter ‘stuadd’ [-Wunused-parameter]
void student_update(char *stuadd)
^~~~~~
Compilation failed.
There are some other problems, like:
free(temp);
free(temp->name);
That is accessing a pointer into allocated memory after the allocated memory has been passed to free() The result is indefined behavior. Suggest:
free(temp->name);
free(temp);
Regarding the following statements
FILE *fptr;
fptr = fopen("stuadd.txt", "a+");
struct student *temp = (struct student *)malloc(sizeof(struct student));
if (fptr == NULL)
printf("\nError.");
Always check for an error indication immediately after the call to the C library function.
output error messages to stderr, not stdout
When the error indication is from a C library function, then immediately call perror(); to output both your error message AND the text reason the system thinks the error occurred, all to stderr
when calling any of the heap allocation functions: malloc calloc realloc, 1) the returned type is void* which can be assigned to any pointer. Casting just clutters the code, making it more difficult to understand, debug, etc. 2) always check (!=NULL) the returned value to assure the operation was successful. Suggest:
FILE *fptr;
fptr = fopen("stuadd.txt", "a+");
if ( !fptr )
{
perror("fopen failed");
exit( EXIT_FAILURE );
}
// implied else, fopen successful
struct student *temp = malloc(sizeof(struct student));
if( !temp )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
regarding:
scanf(" %[^\n]s", temp->name);
That call to scanf() is nonsense. Since the input format specifier %[^\n] will stop input from stdin when it encounters a newline sequence, there is no possible way for the next char in stdin to be a s When calling any of the scanf() family of functions, always check the returned value to assure the operation was successful. when using the input format specifiers %s and/or %[...] always include a MAX CHARACTERS modifier that is one less than the length of the input buffer to avoid any possibility of buffer overflow (and the resulting undefined behavior). Suggest removing the trailing s in the format string and check the return value and limiting the total number of characters that can be input, as in:
if( scanf(" %29[^\n]", temp->name) != 1 )
{
fprintf( stderr, "scanf failed to input the student name\n" );
exit( EXIT_FAILURE );
}
regarding:
for(j = 0; j < 100; j++)
{
temp->mark = temp->mark + studentArray[j];
}
there is no array studentArray[] so this will never produce the desired results.
regarding the error message:
avg = (float)temp->mark / j;
untitled.c:83:33: error: invalid operands to binary + (have ‘float’ and ‘char *’)
temp->mark = temp->mark + studentArray[j];
of course a 'float` value cannot be added to a pointer to a char array. What were you actually trying to accomplish?
All the above is just the 'tip of the iceburg' of problems in the posted code. Suggest using a debugger and stepping through your code to determine the many problems
Related
I'm trying to make a program in which I can read a file with animals weight and calculate the weight average. I got this error while trying to compile. Does anyone knows why?
funciones.c
#include "header.h"
float count_animals(FILE *file){
float total_animals = 0;
char word[20];
while (fscanf(file, "%s", word) == 1){
total_animals++;
}
return total_animals;
}
float sum_weight_animals(FILE *file){
float sum_weight = 0;
float weight[20];
while (fscanf(file, "%f", weight) == 1){
sum_weight += weight;
}
return sum_weight;
}
header.h
#include <stdio.h>
#define MAXWORD 80
float count_animals(FILE *file);
float sum_weight_animals(FILE *file);
Just in case here's the main.c
Now I have the problem that it's not adding up the sum_weight value in sum_weight_animals function.
#include "header.h"
int main(){
char WORD[MAXWORD];
char file_name[MAXWORD];
FILE *fileptr;
printf("Please, enter a file name: ");
scanf("%s", file_name);
printf("Reading file %s...\n", file_name);
fileptr = fopen(file_name, "r");
if(fileptr == NULL){
fprintf(stderr, "ERROR: The file '%s' doesn't exists\n", file_name);
return 1;
}
float total_animals = count_animals(fileptr);
if (total_animals > 0){
printf("There're %.2f animals.\n", total_animals);
}
else{
fprintf(stderr, "WARNING: File not found or it's empty\n");
}
float total_sum = sum_weight_animals(fileptr);
if (total_sum > 0){
printf("The sum of all animal's weight is %.2f [kg].\n", total_sum);
}
else{
fprintf(stderr,"WARNING: File not found or it's empty\n");
}
fclose(fileptr);
return 0;
}
When ex Makefile, it compiles correctly and the first function works fine, but the second one doesn't and it gives me the WARNING: File not found or it's empty\n that I put on main.c
Replace
float weight[20];
with
float weight;
and replace
fscanf(file, "%f", weight)
with
fscanf(file, "%f", &weight)
Explanation:
sum_weight += weight;
is basically equivalent to
sum_weight = sum_weight + weight;
Let's look at the right-hand side, sum_weight + weight.
sum_weight is a float.
weight is an array of 20 float elements.
What does it mean to add a float and an array together? Nothing, that's what. This makes no sense.
You assigned a value to weight[0], and this is the value you want to add. Not weight.
But why is weight an array in the first place? As the name implies, it's only used to store one weight. You only ever assign to weight[0]. So it makes no sense to use an array.
After I execute the exe I get this error :
undefined reference to `StudentScan'
error: ld returned 1 exit status|
Note: I'm bad and new to coding so don't mind my bad coding please^^
Note2: I'm just messing with random functions.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main() {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
return 0;
}
The posted code has defined StudentScan() within main(). But nested function definitions are not allowed in C. This should generate a compiler warning, such as:
warning: ISO C forbids nested functions [-Wpedantic]
void StudentScan(int i, struct student list[])
Pay attention to all compiler warnings and fix them. If no warning is seen when compiling this code, turn up the level of compiler warnings. On gcc, I suggest to always use at least gcc -Wall -Wextra, and I always add -Wpedantic. The -Wpedantic is needed with gcc to see a warning for this. Some compilers, and gcc is one of these, do support nested function definitions as a compiler extension. Still, this feature is nonstandard, and it is best to not rely on it.
The fix is simple: move the definition of StudentScan() out of main():
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
Also note that you should always specify maximum widths when reading strings using scanf() family functions with %s or %[] to avoid buffer overflow. For example:
scanf("%19s", list[i].firstName);
Note that 19 is used, even though the firstName field is an array of 20 char values. Remember that one space must be reserved for the \0 terminator. And since you are using %s to read a string into the AverageNum field, you should also have:
scanf("%1s", list[i].AverageNum);
That is, this field can only hold one digit. If the intention is to hold two digits, this field must be changed within the struct to: char AverageNum[3].
And while we are discussing scanf(), note that this function returns the number of successful assignments made during the function call. If no assignments are made, 0 is returned. This return value should always be checked. Consider: if the user mistakenly enters a letter when a digit is expected, nothing is stored in the intended variable. This may lead to undefined behavior. You may try something like this to validate numeric input:
printf ("\nEnter the host of students: ");
while (scanf ("%d ", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
This code asks the user to enter input again if a number is not entered when expected. Note that if the user does enter a non-digit, this character remains in the input stream and must be cleared before attempting to process more user input. The while loop is a typical construction which accomplishes this task.
Edit
Based on comments made by the OP, here is a modified version of the posted code. This version uses a float value instead of a character array for the AverageNum field of the struct. A floating-point type may be more useful than an integer type for storing averages. It is usually best to use double for floating-point values, but in this case it looks like AverageNum has little need for precision (the char array was intended to hold only two digits); float is probably sufficient for this use. If a different type is desired, it is simple enough to modify the code below.
Some input validation is implemented, but note that more could be done. The user is prompted to enter a number when non-numeric input is found where numeric input is expected. The input stream is cleaned with the while loop construction after such an input mistake; it would be good to remove this code to a separate function called clear_input(), for example.
If the user signals end-of-file from the keyboard, scanf() will return EOF; the code below chooses to exit with an error message rather than continue with malformed input in this case. This could also occur with input redirected from a file, and this condition may need to be handled differently if such input is expected.
The loop that populated the list[] array seemed to be operating inefficiently, asking for AverageNum twice in each pass. This has been streamlined.
Note that the call to malloc() can be rewritten as:
studentp = malloc(length * sizeof *studentp);
This is a very idiomatic way of writing such an allocation. Here, instead of using an explicit type as the operand of sizeof, that is, instead of sizeof (struct student), the variable which holds the address of the allocation is used. sizeof only uses the type of the expression *studentp, so this variable is not dereferenced here. Coding this way is less error-prone and easier to maintain when types change during the maintenance life of the code.
Yet, it is unclear why memory is allocated for studentp in the first place. In the posted code, both the firstName and AverageNum fields are filled for members of the dynamically allocated studentp in calls to StudentScan() in a loop; the same loop fills the AverageNum field of the members of list[] (a different array of structs) with different input. There seems to be no need for one of these arrays of student structs; I have commented-out the dynamically allocated array in favor of the statically allocated version.
Here is the modified code:
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
float AverageNum;
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
// struct student *studentp;
printf ("\nEnter the host of students: ");
while (scanf ("%d", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
struct student list[length];
/* This is fine */
// studentp = malloc(length * sizeof (struct student));
/* But this is better */
// studentp = malloc(length * sizeof *studentp);
// if (studentp == NULL)
// {
/* Not wrong, but... */
// printf("Out of memory!");
// return 0;
// fprintf(stderr, "Allocation failure\n");
// exit(EXIT_FAILURE);
// }
for(i = 0; i < length; i++) {
StudentScan(i, list);
}
/* Code to display results here */
// free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{
putchar('\n');
printf("Enter first name: ");
if (scanf("%19s", list[i].firstName) != 1) {
puts("Input error");
exit(EXIT_FAILURE);
}
printf("Enter average number: ");
while (scanf("%f", &list[i].AverageNum) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
}
You have to remove the scan function from the main. Also there is not a printstudent function you are declaring. You must remove /n from the printf and the scanf functions and place them accordingly. You can then test if your data are being added correctly in your struct with a simple loop.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
int main() {
int i=0;
int length;
struct student *studentp;
printf ("Enter the host of students:");
scanf ("%d", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
printf("Enter first name :");
scanf("%s", list[i].firstName);
printf("Enter average number: ");
scanf("%1s", list[i].AverageNum);
}
for(i = 0; i< length; i++){
printf("number of host is: %d , his/her first name: %s , his/her avg number: %s \n", i, list[i].firstName, list[i].AverageNum);
}
free (studentp);
return 0;
}
I am trying to do a letter guessing game in C language by using Visual Studio 2012, but I keep getting errors and warnings and I have no clue how to fix them. The errors that I keep receiving are:
1.)Warning 1 warning C4133: 'function' : incompatible types - from 'FILE *' to 'const char *'
2.)Warning 2 warning C4047: '=' : 'FILE *' differs in levels of indirection from 'int (__cdecl *)(FILE *)'
3.)Error 3 error C2449: found '{' at file scope (missing function header?)
4.)Error 4 error C1004: unexpected end-of-file found
5.)IntelliSense: argument of type "FILE *" is incompatible with parameter
6.)IntelliSense: a value of type "int (__cdecl *)(FILE *_File)" cannot be assigned to an entity of type "FILE *"
I also see errors that say 'expected a declaration.'
Every time I try to fix things, I end up causing more issues in other areas. Could someone give me assistance with this? Thank you!
Here is my code:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define MAXGUESSES 5
int SingleGame(char file_letter);
int main()
{
//declare additional variables
int PlayGames = 4,
i = 0;
FILE * infile;
char letter;
//display instructions
printf("Welcome to the Letter Guessing Game!\n");
printf("You will enter the number of games that you want to play, which is 1-4 games\n");
printf("You have 5 chances to guess each letter\n");
printf("Let's begin!\n");
//open file
infile = fopen("lettersin.txt", "r");
//get number of games to play
printf("How many games would you like to play?(1-4)\n");
scanf("%d", &PlayGames);
for(i=0;i<PlayGames;i++)
{
//get a letter from file
scanf(infile, " %c", &letter);
//Play one game
printf("Let's play a game %d\n", i);
//check for win or lose
SingleGame (letter);
}
//close file
infile = fclose;
return 0;
}
int SingleGame(char file_letter);
{
//Function definitions
int numGuesses = 0;
while(numGuesses < MAXGUESSES);
char RetrieveGuess = 0;
int PlayGames = 0;
{
printf("Enter a guess\n");
scanf("%c" , &RetrieveGuess);
if(file_letter == RetrieveGuess);
{
printf("You guessed it!\n");
}
else
{
if(file_letter>RetrieveGuess)
{
printf("The letter you are trying to guess comes before:%d\n",RetrieveGuess)
}
{
else if(file_letter<RetrieveGuess)
{
printf("The letter you are trying to guess comes after:%d\n", RetrieveGuess)
}
{
numGuesses = numGuesses +1;
}
1.)Warning 1 warning C4133: 'function' : incompatible types - from 'FILE *' to 'const char *'
scanf(infile, " %c", &letter);
If you want to read from a specific FILE *, use fscanf():
fscanf(infile, " %c", &letter);
2.)Warning 2 warning C4047: '=' : 'FILE *' differs in levels of indirection from 'int (__cdecl *)(FILE *)'
infile = fclose;
You want to call fclose() and not assign it to infile (which also doesn't have a compatible type):
fclose(infile);
3.)Error 3 error C2449: found '{' at file scope (missing function header?)
int SingleGame(char file_letter);
The semicolon makes that a function declaration/protoype, but you want to define one. Delete it.
The semicolon here is a so-called null statement). This means if both variables are equal, then nothing will be done.
if(file_letter == RetrieveGuess);
You have a number of issues with your code here. It is always difficult to work on more than one problem at a time. My advice is that you copy all this code into a different file, and rebuild this file one line at a time and only add another line after you compile the current file error and warning free.
Lots of syntax errors were in code. I've corrected them for you. Although not sure logically the code is correct or not. You got to run and see.
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define MAXGUESSES 5
void SingleGame(char file_letter);
int main()
{
//declare additional variables
int PlayGames = 4,
i = 0;
FILE* infile;
char letter;
//display instructions
printf("Welcome to the Letter Guessing Game!\n");
printf("You will enter the number of games that you want to play, which is 1-4 games\n");
printf("You have 5 chances to guess each letter\n");
printf("Let's begin!\n");
//open file
infile = fopen("lettersin.txt", "r");
//get number of games to play
printf("How many games would you like to play?(1-4)\n");
scanf("%d", &PlayGames);
for(i=0;i<PlayGames;i++)
{
//get a letter from file
fscanf(infile, " %c", &letter);
//Play one game
printf("Let's play a game %d\n", i);
//check for win or lose
SingleGame (letter);
}
//close file
fclose(infile);
return 0;
}
void SingleGame(char file_letter)
{
//Function definitions
int numGuesses = 0;
while(numGuesses < MAXGUESSES)
{
char RetrieveGuess = 0;
int PlayGames = 0;
printf("Enter a guess\n");
scanf("%c" , &RetrieveGuess);
if(file_letter == RetrieveGuess)
{
printf("You guessed it!\n");
}
else
{
if(file_letter>RetrieveGuess)
{
printf("The letter you are trying to guess comes before:%d\n",RetrieveGuess);
}
else if(file_letter<RetrieveGuess)
{
printf("The letter you are trying to guess comes after:%d\n", RetrieveGuess);
}
numGuesses = numGuesses +1;
}
}
}
I have written the following code segment and am having trouble understanding why it would not get to the last printf line. I get a segfault immediately after line 4. The kill_char is just used to kill the 'enter' character added in the previous scanf. Any help would be greatly appreciated, thanks!
int remove = 0;
char kill_char = 'a';
printf("Enter the product number to be removed: ");
scanf("%d", &remove);
scanf("%c", &kill_char);
printf("Does not get here");
EDIT:
Full code is as follows, with the error in the removeProduct function
#include <stdio.h>
#include <stdlib.h>
struct product_node {
char *supply_type;
long number;
char *description;
float price;
int quantity_bought;
float retail_price;
int quantity_sold;
struct product_node *next;
};
struct product_node *head;//declaring head out here
//allows the list to be in scope for the functions
/*Function Prototypes*/
void addProduct();
void removeProduct();
void listProduct();
void listSupplierTypes();
void supplierTypeProfit();
void totalProfit();
void addProduct(){
char kill_char = 'a';//used to kill the enter characters
struct product_node *new_node;
new_node = malloc(sizeof(struct product_node));
printf("\nEnter a string for type: ");
scanf( "%s", &(*new_node).supply_type);
scanf("%c", &kill_char);
printf("Enter the product number: ");
scanf("%ld", &(*new_node).number);
scanf("%c", &kill_char);
printf("Enter the description: ");
scanf("%s", &(*new_node).description);
scanf("%c", &kill_char);
printf("Enter the wholesale price: ");
scanf("%f", &(*new_node).price);
scanf("%c", &kill_char);
printf("Enter the quantity bought: ");
scanf("%d", &(*new_node).quantity_bought);
scanf("%c", &kill_char);
printf("Enter the retail price: ");
scanf("%f", &(*new_node).retail_price);
scanf("%c", &kill_char);
printf("Enter the quantity sold: ");
scanf("%d", &(*new_node).quantity_sold);
scanf("%c", &kill_char);
struct product_node *walker;
walker = head;
int can_insert = 1;
while (!(walker == NULL))
{
if (((*walker).number == (*new_node).number) && ((*walker).supply_type == (*new_node).supply_type))
{
can_insert = 0;
}
walker = (*walker).next;
}
if (can_insert==1)
{
(*new_node).next = head;
head = new_node;
printf("Insertion Successful");
}
else
{
printf("\nERROR INSERTING:This product name and number is already in the list\n");
}
free(new_node);
}
void removeProduct(){
int remove = 0;
char kill_char = 'a';
printf("Enter the product number to be removed: ");
scanf("%d", &remove);
scanf("%c", &kill_char);
printf("Does not get here");
struct product_node *walker;
struct product_node *prev;
prev = head;
walker = (*head).next;
if ((*prev).number == remove)
{
head = walker;
}//points head to second node to remove first
while (!(walker = NULL))
{
if ((*walker).number == remove)
{
(*prev).next = (*walker).next;
}
}
}
void listProduct(){
printf("Still unsure what defines a supplier...");
}
void listSupplierTypes(){
printf("Same as above");
}
void supplierTypeProfit(){
printf("Again");
}
void totalProfit(){
float total = 0.0;
struct product_node *walker;
walker = head;
while(!(walker == NULL))
{
total += ((float)(*walker).quantity_sold * (*walker).retail_price) - ((float)(*walker).quantity_bought * (*walker).price);
walker = (*walker).next;
}
printf("Total Profit is: $%.2f\n", total);
}
int main()
{
head = NULL;
char *temp_type;
char *temp_description;
int temp_number, temp_quantity_bought, temp_quantity_sold;
float temp_price, temp_retail_price;
while(!feof(stdin))
{
scanf( "%s %ld %s %f %d %f %d\n", &temp_type, &temp_number, &temp_description, &temp_price, &temp_quantity_bought, &temp_retail_price, &temp_quantity_sold);
struct product_node *new_node;
new_node = malloc(sizeof(struct product_node));
(*new_node).next = head;
head = new_node;
(*head).supply_type = temp_type;
(*head).number = temp_number;
(*head).description = temp_description;
(*head).price = temp_price;
(*head).quantity_bought = temp_quantity_bought;
(*head).retail_price = temp_retail_price;
(*head).quantity_sold = temp_quantity_sold;
}
freopen("/dev/tty", "rw", stdin);
int done=0;
int selection=0;
while (!done)
{
printf("\nMENU OPTIONS:\n");
printf("1. Add a product number\n");//Okay
printf("2. Remove a product number\n");
printf("3. List the products for a supplier\n");
printf("4. List all unique supplier types\n");
printf("5. Show profit margin for a specific supplier type\n");
printf("6. Show total profit\n");//Okay
printf("7. Quit\n");//Okay
printf("Enter a selection (1-7): ");
scanf("%d", &selection);
char garbage = 'a';
scanf("%c", &garbage);
switch(selection){
case 1:
addProduct();
break;
case 2:
removeProduct();
break;
case 3:
listProduct();
break;
case 4:
listSupplierTypes();
break;
case 5:
supplierTypeProfit();
break;
case 6:
totalProfit();
break;
case 7:
done = 1;
break;
default:
printf("Invalid selection.\n");
break;
}
}
}
remove is the name of a standard function, declared in <stdio.h>. Defining your own object or other entity with the same name has undefined behavior. The call may be trying to store an int value at the address of the remove() function.
Try picking a different name.
UPDATE: I think I was mistaken. Function names defined in standard headers are reserved for use as identifiers with external linkage; they're also reserved for use as a macro name and as an identifier with file scope if the relevant header is #included. Neither should apply in your case. It's still a good idea to avoid defining such identifiers yourself, though.
Also, this probably isn't related to the symptom you're seeing, but
scanf("%d", &obj);
has undefined behavior if the input is a syntactically valid integer whose value is outside the range of int.
Execution does reach your "Does not get here" line. You're not seeing it because the buffered output isn't printed before the program dies. Change this:
printf("Does not get here");
to this:
printf("Does not get here\n");
fflush(stdout);
When I run your program under gdb, I see the seg fault at:
if ((*walker).number == remove)
I also get several warnings during compilation:
c.c: In function ‘addProduct’:
c.c:32:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
c.c:38:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
c.c: In function ‘main’:
c.c:134:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat]
c.c:134:9: warning: format ‘%ld’ expects argument of type ‘long int *’, but argument 3 has type ‘int *’ [-Wformat]
c.c:134:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 4 has type ‘char **’ [-Wformat]
which could easily cause memory corruption. Fix those and see what happens.
UPDATE 2:
I don't know what other programs your code may still have, but this:
while (!(walker = NULL))
{
if ((*walker).number == remove)
{
(*prev).next = (*walker).next;
}
}
is almost certainly wrong. You're using an assignment = operator where you probably want an equality comparison ==. And after fixing that, the code would be clearer as follows:
while (walker != NULL)
{
if (walker->number == remove)
{
prev->next = walker->next;
}
}
That's just what jumped out at me when I took a very quick look after gdb told me the segfault was on the line if ((*walker).number == remove).
Try using a debugger yourself, fix one problem at a time, and pay attention to any compiler warnings.
Your printf does not appear because it didn't flush from the buffer, just use a "\n" at the end of the string and you will see it:
printf("Does not get here\n");
And so, the error, is not at scanf, but at this line:
walker = (*head).next;
As I could see, the program may reach there while head is not allocated, so you can check it at the beginning of the function:
void removeProduct(){
int remove = 0;
char kill_char = 'a';
if (head == NULL) {
printf("No product to remove!\n");
return;
}
I'm not sure if there is any other errors, but this is the one I noticed.
BTW, you can avoid using kill_char by inserting a space at the beginning and end of format string on scanf:
scanf(" %d ", &remove);
It will skip all white characters (as tabs, spaces and line breakers). And, if you really just want to skip one, and only one, character, you can use * to ignore the match:
scanf("%d%*c", &remove);
#include <stdio.h>
#include <string.h>
main()
{
int i;
int *b, *z;
char name[30];
char vowel[5] = {'A', 'E', 'I', 'O', 'U'};
char consonants[23] = {'B','C','D','F','G','H','J','K','L','M','N','P','Q','R','S','T','V','W','X','Y','Z'};
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++){
if
(b=strchr(vowel, name[i]) != NULL) {
printf ("The vowels are: %s\n", b); }
else if
(z=strchr(consonants, name[i]) != NULL) {
printf ("The consonants are: %s\n", z);
}
}
}
I am trying to find how many vowels and consonants in array. That's the only algorithm that our teacher showed us, but it doesn't work. Any one can point me to my mistakes?
I just did one more try, with all your advices,
#include <stdio.h>
#include <string.h>
int main()
{
int vow, cons, i;
char *s, *s1;
char name[30];
char vowel[6] = "AEIOU";
char consonants[21] = "BCDFGHJKLMNPQRSTVWXYZ";
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++)
s = strchr(vowel, name[i]);
printf ("The vowels are: %s\n", s);
s1 =strchr(consonants, name[i])) {
printf ("The consonants are: %s\n", s1);
}
return 0;
}
This is how I changed it, with all your advices, what is my other problems? cause still dosen't work fine.
Thanks.
And this is my another version of program
#include <stdio.h>
#include <string.h>
int main()
{
int i;
int counter=0, counter2=0;
char *s;
char name[30];
char vowel[6] = "AEIOU";
char consonants[21] = "BCDFGHJKLMNPQRSTVWXYZ";
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++) {
if (s = strchr(vowel, name[i])) {
counter++;
}
else if (s =strchr(consonants, name[i])) {
counter2++;
}
printf ("First counter is %d\n", counter);
printf ("The second counter is %d\n", counter2);
return 0;
}
}
I added counters to count quantity of vowels and consonants, still doesn't work.
strchr() is for searching in strings.
char vowel[] = "AEIOU";
char consonants[] = "BCDFGHJKLMNPQRSTVWXYZ";
#include< stdio.h>
int main()
{
int vowel=0,consonant=0;
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for(int i=0;name[i] !='\0';i++)
{
if( name[i] == 'A' || name[i] == 'E' || name[i] == 'I' || name[i] == 'O' || name[i] == 'U' )
{
vowel++;
}
else
consanant++;
}
printf("%d %d",vowel,consonant);
return 0;
}
When I compile this, I get the following messages:
$ gcc -Wall vc.c
vc.c:4:1: warning: return type defaults to ‘int’ [-Wreturn-type]
vc.c: In function ‘main’:
vc.c:17:8: warning: assignment makes pointer from integer without a cast [enabled by default]
vc.c:17:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
vc.c:18:4: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int *’ [-Wformat]
vc.c:20:13: warning: assignment makes pointer from integer without a cast [enabled by default]
vc.c:20:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
vc.c:21:4: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int *’ [-Wformat]
vc.c:24:1: warning: control reaches end of non-void function [-Wreturn-type]
So, start by making sure that your return type for main is 'int'
int main(){
and adding a return at the bottom of the function
return 0;
Thereafter, set b and z to be char *s, so that they match the return type of strchr
char *b, *z;
This will get rid of all the warnings.
$ gcc -Wall vc.c
$
Excellent. Now, when we run your program:
$ ./a.out
input the string: aaa
The string is aaa
Segmentation fault
"Segmentation fault" means you're running off the end of an array and reading memory you don't own. Now implement Ignacio Vazquez-Abrams' solution
char vowel[] = "AEIOU";
char consonants[] = "BCDFGHJKLMNPQRSTVWXYZ";
Now your program will run to completion.
$ ./a.out
input the string: AAA
The string is AAA
The vowels are: AEIOU
The vowels are: AEIOU
The vowels are: AEIOU
But it doesn't do much, does it?
So, if you're just trying to count how many vowels and consonants there are, you can just add an integer for each that increments every time the correct type is found and output them at the end:
printf("Vowels:\t%d\nConsonants:\t%d", vowelsFound, consonantsFound);
However, if you're trying to output them as lists, you're going to have much more data manipulation to do. Some links to check out:
Linux Man Page for printf
Linux Man Page for String functions
You have placed the return statement inside the for loop which is preventing it from scanning the entire name array.
When using strchr, you'll also need to convert the current loop character to uppercase for it to match properly since you have defined vowels in uppercase. To use toupper() you need to include ctype.h.
You also don't need to define consonants. What is not a vowel is a consonant.
Here's the code. I've tested it and it works:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
int i;
int counter=0, counter2=0;
char *s;
char name[30];
char vowel[6] = "AEIOU";
printf ("input the string: ");
scanf ("%s", name);
printf ("The string is %s\n", name);
for (i=0; name[i]!='\0'; i++) {
if (strchr(vowel, toupper(name[i])) != NULL) {
counter++;
}
else {
counter2++;
}
}
printf ("First counter is %d\n", counter);
printf ("The second counter is %d\n", counter2);
return 0;
}
Alternatively.
#include <stdio.h>
#include <string.h>
int main() {
int t [256];
int i,c;
int cntw = 0;
int cntc = 0;
const char * vowel="AEIOUaeiou";
const char * consonants="BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
memset(t,0,256);
while (*vowel) { t[*vowel] = 1; ++vowel;}
while (*consonants) { t[*consonants] = 2; ++consonants;}
printf ("Input the text: CTRL-D to end\n");
c = getchar();
while(c >=0) {
switch(t[c]) {
case 1: ++cntw; break;
case 2: ++cntc; break;
}
c=getchar();
}
printf ("Text has %d vowel%s and %d consonant%s\n",
cntw,(cntw>1)?"s":"",
cntc,(cntc>1)?"s":"");
return 0;
}