How exactly does space work with scanf? - c

I am a math student, and I'm learning the very basics in programming in C. I need a program to read an input consisting in an array, the components of which must have certain requisites; I would like the program to ask the user for the components of the array. The user should then have to enter such components separating them with spaces. The details aren't important to get the main question across; I'll choose a simpler example then the one I am dealing with: let's say I want an array with 6 components not to contain the number 4. So I tried:
#include <stdio.h>
int main(void) {
int a[6];
printf("enter components: ");
int i;
for (i = 0; i < 6; i++) {
scanf("%d", &a[i]);
if (a[i] == 4) printf(" \n\n4 is not allowed, try again\n\n");
}
for (i = 0; i < 6; i++) {
printf("%d ", a[i]);
}
}
If I compile this and run it, and for example enter:
1 2 3 4 5 6
I will get my error message, but only after having pressed enter, that is after having entered all six components (not straight after having pressed space for the fourth time). So here are my questions (I am looking for solutions which don't make use of strings or pointers, unless it is impossible to do without them):
Is there a way to get the program to read a component (and to act accordingly) straight after its subsequent space has been entered? I'm guessing there isn't because scanf only works after the user presses enter, and not space, correct?
If there isn't, is there a way to get the program to read the components all at once after having pressed enter at the end, but letting the user pick up from the last right component? For example, with the above input, I would like the program to display something like this:
4 is not allowed
1 2 3 _
so that the user can correct his/her input (possibly changing the first three digits as well).
Sorry if this question is too dumb! Thank you for your help!!
EDIT: Well, thanks for the great answers, you have all been very helpful! It's a pity I can't accept more than one.

In for loop, after each iteration, the counter add by one automatically. If you get an invalid input, you should prevent the counter increasing. To do this, just add i--; to your code when you give an invalid input.
#include <stdio.h>
int main(void) {
int a[6];
printf("enter components: ");
int i;
for (i = 0; i < 6; i++) {
scanf("%d", &a[i]);
if (a[i] == 4){
printf(" \n\n4 is not allowed, try again\n\n");
i--;
}
}
for (i = 0; i < 6; i++) {
printf("%d ", a[i]);
}
}

Please see the bellow code:
#include <stdio.h>
int main(void) {
int a[6];
int i;
bool hasError = false;
int errorIndex = 0;
do{
hasError = false;
printf("enter components: ");
for (i = 0; i < errorIndex; i++)
printf("%d ", a[i]);
for (i = errorIndex; i < 6; i++) {
scanf("%d", &a[i]);
if (a[i] == 4 && hasError == false){
printf(" \n\n4 is not allowed, try again\n\n");
hasError = true;
errorIndex = i;
}
}
}while(hasError == true);
for (i = 0; i < 6; i++) {
printf("%d ", a[i]);
}
}

This is related to your terminal being in "cooked" mode. Characters aren't even sent to the program until the user presses enter.

You could do something like this:
int i,a[6];
for (int i=0;i<6;i++) {
scan: scanf("%d",&a[i]);
}
for (int i=0;i<6;i++) if (a[i]==4) {
printf("4 is not allowed. re-enter the last %d numbers\n",6-i);
goto scan;
}
note that in most case, it's better to avoid using goto, but in this case I think that it's natural.
If you really want, you can print the first i numbers (before the goto), but it's complicated (and platform-depended) to let the user change those numbers.

Improving on Mir Milad Hosseiny answer (I wrongly identified it as being an out of control infinite loop... it's actually exactly the infinite loop I describe in my comment)...
I would write a small function that has either a "white list" (things you want) or a "black list" things you don't want, and check each value to either belong or not (depending on the approach) to the list. That way you can keep a separate place where your store the values that you are willing to accept or the values you are not, so your primary function doesn't get really messy with exceptions or inclusions in the "if"
so your code would be
if(isAllowed(a[i]){
myList[j] = a[i]; //j is your alternate counter
}

Related

Trying to make a simple C program to take names from the user and display them all

Trying to make a simple program to take names from the user and display them all.
#include <stdio.h>
#define COMPETITOR 16
#define NAME_LENGTH 25
int main(void)
{
char name[COMPETITOR][NAME_LENGTH];
int i;
for(i = 0; i < COMPETITOR; i++);
{
printf("Enter Competitor's name: ");
scanf("%24[^\n]%*c", name[i]);
}
for(int i = 0; i < COMPETITOR; ++i)
{
printf("%s\n", name[i]);
}
return 0;
}
However, it returns some really annoying results and I can't figure out why.
Enter Competitor's name: oheuthere
D
X│∞Ω√⌂
p#
δΩ√⌂
--------------------------------
Process exited after 5.747 seconds with return value 0
Press any key to continue . . .
I have noticed that if I change the value of #define COMPETITOR 16 it changes the characters that appear and I'm even getting emoji...
Any help to figure out what's going on would be amazing ahaha since I've followed exactly what the lecturer did and its still wack
This for loop for(i = 0; i < COMPETITOR; i++); has a semicolon on the end of it, meaning it will not run the block next to it. So with this code you are scanning only the i line, witch isn't initialized, and printing trash from the memory after that.

My C program to find closest pair of numbers from user input is not printing the right output?

I am trying to find the closest pair of numbers entered by the user. My C code isn't working right and I can't figure out what's wrong. I think it might have something to do with storing the values but I don't know where to go from here.
#include <stdio.h>
#include <math.h>
int main()
{
int i, j,arr[50], first,second;
//loop input
for(i=0;i<50;i++) //loop 50 times
{
scanf("%d", &i); //scan
//break if i=-1
if (i==-1)
break;
//if not print
}
//2nd num - 1st num < 3rd num-1st num, closest = 1st and 2nd num
//i[0]=num1, j[0+i]=2nd num, i= 4 , 5, 7, ans=arr,
//if j[0+i]-i[0]= ans < j[0+i]-i[i]=ans
//arr[i]=8,2,17,4,25
for(i=0;i<50;i++)
{
for(j=i+1;j<50;j++)
{
if(arr[j]-arr[i]<arr[j+1]-arr[i])
{
first = arr[i];//3
second = arr[j+1];//5
}
}
}
printf("%d %d\n", first, second);
return 0;
}
Don't post it as answer, prefer editing your code instead. Anyway, the problem is here :
for (j = i + 1; j < len; j++)//j<i <-why is it wrong?
How isn't it wrong? You've initialised j with the value i+1. How's it supposed to be ever less than i? And due to that, it's picking up values from outside the array and providing you with unexpected results.
The correct form is :
for (j = 0; j < i; j++)
The problem is with this chunk of code. You're scanning in the counter variable i instead of array. And then you're manipulating stuff using array arr. Why should that work in any scenario?
for(i=0;i<50;i++) //loop 50 times
{
scanf("%d", &i); //scan
//break if i=-1
if (i==-1)
break;
//if not print
}
And i can never be -1 unless it's a miracle.

How can I integrate modularity into my code in C?

I don't know much about modularity except it's basically dividing up your code into smaller groups of functions (this question is for the C language).
I'm doing an assignment where I can only see my source code working with one giant nested loop in "main" (no if statements are allowed for the assignment). In other words, if I try and use functions to cut up the code, I don't see how the necessary nested loop will work. But the assignment requires an attempt at modularity.
Thus, can anyone tell me how I might break up the following code into smaller modules without messing up its actual execution?
#include <stdio.h>
int main(void)
{
int counter = 0;
int marknum = 0;
int sectioncode, studentnumber;
int dummyvariable = 0;
int index;
int marks;
int total = 0;
do
{
printf("Enter a Section Code: ");
scanf("%d", &sectioncode);
while(sectioncode > 4 || sectioncode < 1)
{
printf("Invalid value entered. Must be 1 to 4, please re-enter: ");
scanf("%d", &sectioncode);
}
do
{
printf("Enter the Student's ID: ");
scanf("%d", &studentnumber);
while (studentnumber < 1 || studentnumber > 999999999)
{
printf("Invalid value entered. Must be 1 to 999999999. Please re-enter: ");
scanf("%d", &studentnumber);
}
while (sectioncode != 0)
{
while (counter < 5)
{
counter++;
marknum++;
printf("Enter mark%d: ", marknum);
scanf("%d", &marks);
total = total + marks;
}
printf("%09d's total mark is %d\n", studentnumber, total);
counter = 0;
marknum = 0;
sectioncode = 0;
}
dummyvariable = 1;
} while (dummyvariable = 0);
} while (sectioncode != 0);
return 0;
}
Also, how would I incorporate modularity for this one (same question basically):
#include <stdio.h>
int main(void)
{
int num; //User inputted number
int i; //Increment variable
char ch; //Check for characters variable
do //Begin "do while" loop
{
printf("\nEnter a number:"); //User prompt
scanf ("%d", &num); //Scan for user inputted integer
while ( (ch = getchar()) != '\n') //Scan for character, check for non-numeric input
{
printf("Invalid number entered. Please re-enter: "); //Error message and prompt for invalid user input
scanf ("%d", &num); //Scan for user inputted integer
} //Repeat loop if condition becomes true again
for (i=0; i<num; i++) //Begin "for" loop; condition prints asterisks equal to user number; increment i by 1
{
printf("*"); //Prints a single asterisk each loop until i is less than num
}
} while (num!=0); //Stop "do while" loop if user enters 0
return 0;
}
Normally I'd suggest that you ask your instructor instead of asking homework questions here, but as Daniel points out in the comments, the use of loops and extra variables just to avoid having if statements in the code is stupid, and I'm not sure telling you to get advice from an instructor who thought that was a good idea would be entirely responsible behavior on my part. So, having said that:
What you want to look for in cases like this is multiple chunks of similar code, or chunks of code that conceptually do a single thing. Then see if you can split those chunks out into a function.
In the first example, you display a prompt, read user input, and verify the input for both sectioncode and studentnumber. That process could be split into a separate function. (Everything from printf("Enter ...") through the end of the while loop.) Then in the main function, you just have something like
sectioncode = readval("Enter a Section Code: ", 1, 4);
studentnumber = readval("Enter the Student's ID: ", 1, 999999999);
For the second example, that input/validation code isn't duplicated, but it's still probably worth splitting out into a function, since it does a single well-defined thing, and spans enough lines that splitting it out into a function might help make the logic of the remaining code more clear. But it's less important in this case than in the first.
Also, an unrelated issue: At the end of one of the do-whiles, you have while (dummyvariable = 0);. Note the single equal sign. You're assigning 0 to dummyvariable, not comparing.
In this particular case, it works anyway, since the whole expression evaluates to 0 (i.e. false), just like (dummyvariable == 0) would have. But if that constant had been anything else, or if you hadn't just set dummyvariable to 1 prior to the end of loop, that'd be a bug.
I strongly recommend always putting the constant on the left hand side of expressions like that in order to catch bugs of that sort at compilation. while (dummyvariable = 0) silently does something unexpected; while (0 = dummyvariable) will give an error at compile-time, and you can fix it.

Program gets hung up when I use "delete" function

I'm trying to write a program where it'll take in info from a user, and the user will have options on what to do. The options are to add, modify, delete, display certain info, find the average, and exit.
I have written code for all of them but I can't get my delete function to work.
Here is my code:
void delete_student(struct students *list, int *count) //Delete's Selected student
{
int id4;
int k;
if (*count != 0)
{
printf("\nEnter the ID of the student you wish to delete: ");
scanf("%d\n", &id4);
for (int i = 0; i < *count; i++) //Searches for the selected student
{
k = i;
if (list[i].id == id4)
{
printf("\nStudent found.\nDeleting...\n");
for (int c = k; c < *count; c++) //Deletes the student if found
{
list[c].id = list[c + 1].id;
strcpy(list[c].name, list[c + 1].name);
list[c].age = list[c + 1].age;
strcpy(list[c].dept, list[c + 1].dept);
list[c].grade = list[c + 1].grade;
}
*count = *count - 1;
printf("\nDeletion Complete.\n");
break;
}
else
printf("\nStudent not found. Please try again.\n");
break;
}
}
else
printf("\nNo student's to delete.\n");
}
Edit:
When I go through the program, and I select to use this function, it'll ask me for the "ID" and then it does nothing and has a blinking cursor.
Could someone tell me what I'm doing wrong?
There's more code if you need it.
Is this how the last element would be deleted:
list[*count].id = 0;
strcpy(list[*count].name, NULL);
list[*count].age = 0;
strcpy(list[*count].dept, NULL);
list[*count].grade = 0;
Your scanf() statement has an incorrect format string. You don't need to add the trailing newline; scanf takes care of it. Change that line to scanf("%d", &id4); (no newline) and it should work.
I just wrote a small stub program that compares scanf with and without the newline, and it replicates your error.
You have a break statement at the end of your for loop that probably shouldn't be there. Just delete that one.
else
printf("\nStudent not found. Please try again.\n");
break;
} ^
|
+------ this one
That printf is a bit inaccurate too; it will get printed out on every iteration of the loop where you didn't happen to find a matching ID.
This loop:
for (int c = k; c < *count; c++)
should probably instead be:
for (int c = k; c < *count - 1; c++)
As written, it reads one past the end of the valid array. The results are undefined. And in particular, the strcpy calls may go quite badly. When it gets to the last entry in that loop, list[c+1] refers to an entry that does not exist (based on *count).
Your scanf hangs as it never gets to read your number. No \n needed. Use %d only.

Simple program that adds numbers from user

I am trying to write a simple program that uses scanf to input 5 numbers from the user and add them together. Here is the code I have so far..
int main()
{
int i;
int j=1;
int k=1;
for (i=1; i<= 5; i++)
{
scanf("%d\n", &j);
k = k+j;
}
printf("%d\n", k);
}
But here's what happens when I run the program:
1
2
3
4
5
5
16
Basically, it asks me for a sixth number (obviously, I just need 5), and it also adds one to the final result. (1+2+3+4+5=15).
Any thoughts on this. Am I making a simple mistake somewhere?
As others have said, you are initializing k incorrectly, but I suspect that what's causing your problem is that you are using scanf("%d\n", &j); instead of scanf("%d", &j);. scanf() ignores whitespace leading up to the match.
Initially k = 1. Then you add the numbers 1, 2, 3, 4, 5 to it. Altogether they sum up to 1+1+2+3+4+5, which is 16.
You should generally think about initializing variables.
i doesn't need to be initialized before the for loop.
j doesn't need to be initialized, since it will be read from the input.
k needs to be properly initialized. But since it has a certain purpose you should rather call it sum than k. And when you sum up things, you should start with 0.
Additionally you should check whether the call to scanf was successful. In that case the function returns 1.
if (scanf("%d", &j) == 1) {
sum += j;
} else {
fprintf(stderr, "Invalid input.\n");
break; /* exit the for loop. */
}
You seem to be initializing k (which is the number you hold your sum in) as one, then adding all the other numbers to it. Try this:
int k = 0;
instead.
Then, when you do
k = k+j
the first time, k will be 0, and not 1. You also don't need to do j=1.
That said, you can also use a shortcut for k = k +j;
k += j;
C programmers have to do this pattern so much that they built a shortcut into the language specifically for it.
In your for loop, it's convention in C to start at zero and work to < your max number, as well:
for (i = 0; i < 5; i++)
I'm not sure why it's asking an extra time, but try setting your loop as that and seeing if it works.
This is what you want, k initialized at 0 and doing a scanf input without the \n which is an endline :
int main() {
int i;
int j=0;
int k=0;
for (i=1; i<= 5; i++){
scanf("%d", &j);
k = k+j;
}
printf("%d\n", k);
}
The '\n' character is unnecessary. I suspect you are mixing up your printf and scanf syntax :P

Resources