Can I check a condition for one variable - c

I am writing a program to scan the name, gender, and three monthly checks for a person. Here is an example on what I want entered:
Jack m 200 250 300
If the user types "Enough" and presses enter without filling the other details I want the loop to end. I tried using two scanf's, one for the string alone and one for the others but it doesn't loop properly. Here is my code:
int main()
{
int i;
char names[SIZE][NAME_LEN] = {0}, gender[SIZE] = {0};
int sales[SIZE][SALES_LEN] = {0};
printf("Enter the name, gender and three month sales for name %d: ", i+1);
for (i=0; i<SIZE; i++){
if (strcmp(names[i], "Enough") == 0 || strcmp(names[i], "enough") == 0)
break;
scanf("%s %c %d %d %d",names[i], &gender[i], &sales[i][0],&sales[i][1],&sales[i][2]);
}
return 0;
}

Your code is broken is many places: badly ordered statements and wrong kind of reading and parsing. This may do the trick:
for (i=0; i<SIZE; i++) {
char buffer[100]; // A full line
printf("Enter the name, gender and three month sales for name %d: ", i+1);
if (fgets(buffer,sizeof buffer,stdin)==NULL // if nothing can be read
|| strncasecmp(buffer,"-stop",5)) { // or if user typed "-stop" and whatever, an impossible lastname?
break;
}
// try to convert the line into fields of given types...
if (sscanf(buffer,"%s %c %d %d %d",names[i], &gender[i], &sales[i][0],&sales[i][1],&sales[i][2])!=5) {
// do something if conversions failed
}
}

You could use something like this:
while(gets(line)) { ... }
If user presses only the return key the gets function returns NULL and the cycle stops. This way the user doesn't have to type "Enough".
*Don't use the gets() function because it's unsafe (risk of buffer overflow).
I usually wrap it in a function which controls the length of the input.

Related

Write a program in C to read and print the names of n students of a class

I know this seems a very easy problem but till I am not getting the required output. Please correct any mistakes on asking the question as i am posting question on this site for the first time.
The code I tried is as follows:
#include<stdio.h>
int main()
{
int i, n;
char name[20][80];
printf("\nEnter the number of students: ");
scanf("%d", &n);
printf("\nEnter the name of the students: ");
for(i=0; i<n; i++)
{
fgets(name[i], 80, stdin);
}
printf("\nThe name of the students are: \n");
for(i=0; i<n; i++)
{
puts(name[i]);
}
return 0;
}
But the output is like:
Enter the number of students: 3
Enter the name of students: Park Jimin
Jeon Jungkook
The name of the students are:
Park Jimin
Jeon Jungkook
I can't understand why the number of students became 2 though I mentioned 3.
Please help.
Don't use the scanf family of functions - in my experience they cause more problems than they solve. In this case the issue is that scanf leaves the newline (\n) character in the buffer after you entered the number of students, so a blank line was read the first time your program tried to get a student name. The following should solve your homework problem successfully:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, n;
char buf[20];
char name[20][80];
printf("Enter the number of students: ");
fgets(buf, sizeof(buf), stdin);
n = atoi(buf);
for(i=0; i<n; i++)
{
printf("Enter student name #%d: ", i+1);
fgets(name[i], 80, stdin);
name[i][strlen(name[i])-1] = '\0'; /* overwrite the trailing \n */
}
printf("\nThe names of the students are:\n");
for(i=0; i<n; i++)
printf("name[%d] = \"%s\"\n", i, name[i]);
return 0;
}
OnlineGDB test here
Instead of using fgets and puts use scanf and printf as shown in below code. Below code is working I checked it. You can change it as you want show like with carriage return etc.
int i, n;
char name[20][80];
printf("\nEnter the number of students: ");
scanf("%d", &n);
printf("\nEnter the name of the students: ");
for(i=0; i<n; i++)
{
//fgets(name[i], 80, stdin);
scanf("%s",name[i]);
printf("%d",i);
}
printf("\nThe name of the students are: \n");
for(i=0; i<n; i++)
{
//puts(name[i]);
printf("%d%s",i,name[i]);
}
return 0;
From my pov, the issue here is an unexpected newline character in the input buffer. While this behaviour is known, there are two different approaches to resolve this.
1. Sanitize your inputs:
Simply reading data and working on this data is often a bad idea. Therefore you may want to check, if the data you just got makes sense and is within your expectation. In your example you should never accept an empty name, no matter if comes from buffer artifacts or real user input.
int j = 0;
while(j<n)
{
printf("Write to index: %d", j);
fgets(name[j], 80, stdin);
if (name[j][0] != '\n')
{
j++;
}
}
https://onlinegdb.com/Hy5ZDWq0U
Restructuring your input loop to something like this already gets rid of empty entries. Yet it is not even close to a fully sanitized input as there are numbers, printable and non-printable special characters and length limitations to consider.
The printf("Write to index: %d", j) easily shows you, that the evil newline is still there, but due to our input check it is overridden within the next loop execution. The output loop can remain unchanged and will not print any empty entries anymore.
2. Try to clear the buffer:
Another approach is to clear the buffer in order to get known preconditions before calling fgets or similar functions. Within Using fflush(stdin) you can find a nice discussion on how this can go wrong and why it is rather brittle to do so.
Personally I would always prefer the first over the second solution, as your code should be responsible to handle unexpected inputs according to its needs. Relying on others easily goes wrong, if they do not exactly know, what your expectations are.

If character then redo the function

In C code.
This is the part I want to work on below. I want to be able to do... if a character value then say "not a number", however, because it is an array and it increments I'm not sure how to do such, newbie here, so please explain and show me an example how to do if possible. Have to enter up to 10 values.
So if:
Employee 1 = c
"Not a Number. Try again."
Employee 1 = 5
Employee 2 = 55
Employee 3 = g
"Not a Number. Try again."
Employee 3...etc
void getSalaries(float sal[], int size)
{
int i = 0;
for(i = 0; i < size; i++)
{
printf("Enter salary for Employee #%d: ", i + 1);
if (scanf("%f", &sal[i]) != 1)
{
printf ("Not a number. Please try again.\n");
break;
}
}
}
If you want to repeat something, you need a loop. If you don't know how many times you'll want to loop in advance, it's probably going to be a while loop. The following structure will achieve your goal cleanly:
while (1) {
printf("Enter salary for Employee #%d: ", i + 1);
scanf("%f", &sal[i]);
if (...valid...)
break;
printf("Not a Number. Try again.\n");
}
The value returned by scanf will help you determine if the input was valid. I will leave consulting the documentation and finishing that part of your homework to you.
Some help to get you started, scanf returns the number of successfully read items (matching % marks in format string). So you can evaluate this number and take action accordingly.
int n=scanf("%f", &sal[i]);
if (n !=1){
// do something here
}
Hint: There is a common problem with using scanf,in that it wont recover from a "bad" input, unless you empty the buffer by "eating" the bad string.
If you want to convince your teacher that you have a VERY BIG BRAIN /s, you could do something like this;
#include <stdio.h>
#include <string.h>
void getSalaries (float sal[], int size)
{
char *scan_fmt[2] = {
"%f", // Get float
"%*s%f" // Eat previous bad input, and get float
};
char *cli_mess[2] = {
"Enter salary for Employee #%d: ",
"Try again, for Employee #%d: "
};
for (int i = 0, n=1; i < size; i += n==1){
printf (cli_mess[n!=1], i + 1);
n = scanf (scan_fmt[n!=1], &sal[i]);
}
}
int main ()
{
float s[3];
getSalaries (s, 3);
return 0;
}

Segmentation Fault error due to the addition of one small 2d array

I created a small test program because the same issue was happening in my larger program. I am new to c, so maybe there is something obvious I'm missing. my program asks the user to input the amount of students and amount of courses they would like to add.. I then create an 2d array with the size set to the amount of students by the amount of courses. this 2d array causes a segmentation fault when I test the program only entering in 4 students and 4 courses, meaning there should only be 16 elements. I'm unsure why this causes a seg fault.
int registry[][] is the array in question
I've tested the program with and without the 2d array and it works perfectly fine without it.
int main (void) {
int numOfStds;
int numOfCrs;
int stdNum;
printf("How many students would you like to register:");
scanf("%d", &numOfStds );
printf("How many courses are in the program?:");
scanf("%d", &numOfCrs);
int students[numOfStds];
char courses[numOfCrs][8];
for(int i; i < numOfStds; i++){
printf("Please enter student %d's number:", i);
scanf("%d", &stdNum);
students[i] = stdNum;
}
for(int i; i < numOfCrs; i++){
printf("Please enter course %d's code (must be 7 characters long):", i);
scanf("%s", courses[i]);
}
int registry[numOfStds][numOfCrs];
for(int i; i< numOfCrs; i++){
printf("%s\n", courses[i]);
}
for(int i; i < numOfStds; i++){
printf("%d\n", students[i]);
}
}
In all of your for loops, you are using the index variable i uninitialized. This can cause undefined behavior. Since the behavior is undefined, the presence or absence of the registry array may alter the behavior.
You should initialize i in each for loop like this:
for(int i = 0; i < numOfStds; i++){
I will also echo the concerns raised in David's answer. If you call a function that returns a status, you should always check the status to make sure it is what you expect. It is always better to handle errors as soon as they occur. Your code as written assumes no errors in the input, which is not valid in the general case. This is not a theoretical problem. Practical applications always have the possibility of encountering invalid or malformed input.
As noted in my comments, you have two primary problems. The scanf ("%d/n", ...) format string is just wrong unless the user is actually entering a "/n" after each input and second, your loop variable is uninitialized in each for loop.
But even more troubling is you fail to validate the return of scanf on each call, so a single mistyped character can cause your integer conversion to fail silently and you proceed forward as if nothing is wrong. For example, if reaching for the 3 your user accidentally hits 'e', then a matching-failure occurs, character extraction from stdin stops at that point, and if you are looping collecting integer input, you have just spun off into an infinite loop.
Always Validate Every Input
It takes nothing more than simple validation to save yourself from yourself. To validate you input you can do:
printf("How many students would you like to register: ");
if (scanf ("%d", &numOfStds) != 1) {
fputs ("error: invalid integer input - numOfStds.\n", stderr);
return 1;
}
and for another example:
for(int i = 0; i < numOfStds; i++){
printf ("Please enter student %d's number: ", i+1);
if (scanf("%d", &stdNum) != 1) {
fputs ("error: invalid integer input - stdNum.\n", stderr);
return 1;
}
students[i] = stdNum;
}
Putting it together in a full example, and then outputting the collected values you can do:
#include <stdio.h>
int main (void) {
int numOfStds;
int numOfCrs;
int stdNum;
printf("How many students would you like to register: ");
if (scanf ("%d", &numOfStds) != 1) {
fputs ("error: invalid integer input - numOfStds.\n", stderr);
return 1;
}
printf("How many courses are in the program?: ");
if (scanf ("%d", &numOfCrs) != 1) {
fputs ("error: invalid integer input - numOfCrs.\n", stderr);
return 1;
}
int students[numOfStds];
char courses[numOfCrs][8];
for(int i = 0; i < numOfStds; i++){
printf ("Please enter student %d's number: ", i+1);
if (scanf("%d", &stdNum) != 1) {
fputs ("error: invalid integer input - stdNum.\n", stderr);
return 1;
}
students[i] = stdNum;
}
for(int i = 0; i < numOfCrs; i++){
printf("Please enter course %d's code (must be 7 characters long): ",
i+1);
if (scanf ("%7s", courses[i]) != 1) {
fputs ("error: invalid integer input - numOfCrs.\n", stderr);
return 1;
}
}
/* example output */
// int registry[numOfStds][numOfCrs];
puts ("\nStudents:");
for (int i = 0; i < numOfStds; i++)
printf ("student: %d\n", students[i]);
puts ("\nCourses:");
for (int i = 0; i < numOfCrs; i++)
printf ("course: %s\n", courses[i]);
}
(note: above the protection of your array bounds with if (scanf ("%7s", courses[i]) != 1), if you fail to include the 7 as a field-width modifier, your user can enter as many characters as they wish resulting in Undefined Behavior)
Example Use/Output
$ ./bin/numofstds
How many students would you like to register: 3
How many courses are in the program?: 2
Please enter student 1's number: 301
Please enter student 2's number: 302
Please enter student 3's number: 303
Please enter course 1's code (must be 7 characters long): abcdefg
Please enter course 2's code (must be 7 characters long): bcdefgh
Students:
student: 301
student: 302
student: 303
Courses:
course: abcdefg
course: bcdefgh
Look things over and let me know if you have further questions.

How to find matching values in two arrays?

I need to get the user to input 6 numbers and I store those in an array called winningNum[]. Then I have to read in a file that has a bunch of users firstName lastName and the numbers they have guessed. I need to compare these two arrays and only print out the first and last name of the users from the file that got a minimum of three numbers matched.
This is the struct of for the input file users
typedef struct
{
char firstName [20];
char lastName [20];
int numbers[6];
}KBLottoPlayer;
Getting the winning numbers from the user
int getNum()
{
int winningNum[6];
int i;
printf("Please enter the six nunbers between 1-53:\n");
scanf("%d %d %d %d %d %d", &winningNum[0], &winningNum[1],
&winningNum[2] ,&winningNum[3], &winningNum[4], &winningNum[5] );
}
This is where I am reading in the file and putting it into the struct array
KBLottoPlayer* readArray()
{
int i,size;
FILE *in = fopen("KnightsBall.in","r");
fscanf(in,"%d",&size);
KBLottoPlayer* temp;
temp =(KBLottoPlayer*)malloc(sizeof(KBLottoPlayer)*size);
if((in = fopen("KnightsBall.in", "r")) != NULL )
{
char buffer[100];
fgets(buffer, 5, in);
for(i=0;i<size;i++)
{
fscanf(in," %s %s ", temp[i].firstName, temp[i].lastName);
fscanf(in,"%d %d %d %d %d %d ", &temp[i].numbers[0],
&temp[i].numbers[1], &temp[i].numbers[2], &temp[i].numbers[3],
&temp[i].numbers[4], &temp[i].numbers[5]);
}
}
else
{
printf("File is Not Exist.\n");
}
return temp;
}
I essentially need to only store the first and last name of the users that got 3 4 5 6 of the winning numbers correct.
I will admit that you only need hints to go past a problem.
Unrelated, but you never test your input functions. Beware a single incorrect line will give undefined results and you will not even know where the problem is. Remember: never trust what comes from the outside.
Back to your problem. A simple way is to use 2 nested loops, one on the winning numbers and one on the guessed ones just counting the matches: if the total number of matches is at least 3, you keep the record, else you reject it. You can even do that when reading the file (here in pseudo-code):
int recnum = 0; // next record to store
for (int i=0; i<size; i++) { // loop over the input file
read the line into temp[recnum]
int count = 0; // number of correct guesses
for (int j=0; j<6; j++) { // loop over the winning numbers
for (int k=0; k<6; k++) { // loop over the guessed numbers
if winning[j] == guessed[k] {
count++;
}
}
}
if (count >= 3) recnum++; // only keep if at least 3 correct guesses
}

using array to tally votes

So I'm working on this program where I need to use arrays, to record the sums of votes for a user inputed number of id's where they will vote for an option a,b,c or d. at the end I will print the sum with the highest votes and declare them the winner. This being said, it's understood that no one may vote more than once. This is where my problem is occurring, I'm trying to set the array for id's(voter_id) to have every value in the area be false until the user specifies his id and then votes, where the value should then be 0, at the id spot in the array.
additionally My program is not printing the printf for successfully voting for a candidate. printf("Successfully voted for %c)
#include <stdio.h>
int main(){
int id;
int a_size;
char ch;
int sum[4];
int i;
int max;
int voter_id[a_size];
sum[0]=0;
sum[1]=0;
sum[2]=0;
sum[3]=0;
voter_id[a_size]=1;
//scan for the array size
scanf("%d", &a_size);
//need to loop and scan for characters while incrementing up the array size until we reach the final array slot
while(id>0 && id!=-1){
printf("What is your id?\n");
scanf("%d", &id);
for (i=0;i<a_size;i++){
voter_id[a_size]=1;
printf("You have already voted. You cannot vote again.");
continue;
}
printf("Welcome %d, which vote would you like to place?\n", id);
scanf("%c\n", &ch);
if (ch== 'A' || ch=='a'){
printf("You have successfully voted for A\n");
sum[0]++;
}
if (ch== 'B' || ch=='b'){
printf("You have successfully voted for B\n");
sum[1]++;
}
if (ch== 'C' || ch=='c'){
printf("You have successfully voted for C\n");
sum[2]++;
}
if (ch== 'D' || ch== 'd'){
printf("You have successfully voted for D\n");
sum[3]++;
}
}
max=1;
for(i=0;i<4;i++){
if (sum[i]>max){
max=sum[i];
}
'A'== sum[0];
'B'== sum[1];
'C'== sum[2];
'D'== sum[3];
printf("%c wins with %d votes", &sum[i], &max);
}
return 0;
}
First of all, take the following as advice and spend the required time doing it, it will reward you later
Format your code so it looks beautiful
believe it or not, this can make you a better programmer.
This in a loop causes problems
scanf("%c\n", &ch);
because you input the '\n' when you press enter, and then the scanf() will consume it on the iteration right after the one where you input your data, you need to explicitly ignore white space characters for the "%c" specifier, like this
scanf(" %c\n", &ch);
This comparison 'D'== sum[3]; does absolutely nothing, I suppose that you tried to assign to the character constant and found this as a workaround, which means that you don't understand what the == operator is for, it's for comparison.
This is also wrong
printf("%c wins with %d votes", &sum[i], &max);
because you are passing the address of the ith element in the sum array, and then you pass the address of max which is also wrong.
This means that you don't know why you use the & address of operator in scanf(), there you need to pass the address of the variable to modify it inside scanf() but in the case of printf() what you need to pass is the value.
If you want to check who won, then
int index;
max = sum[0];
index = 0;
for (i = 1 ; i < 4 ; ++i)
{
if (max < sum[i])
{
index = i;
max = sum[i];
}
}
printf("%c wins with %d votes", index + 'A', max);
in this particular case this will work because 'B' == 'A' + 1 and 'C' == 'A' + 2 and so on.

Resources