My Programm looks like this.
int main(){
int maxnote = 0;
int eingabewert;
int n = 0;
int userMarks[200];
ind promark;
printf("Welcome, plese enter your points, -1 to finish.\n");
while (eingabewert != -1){
scanf("%d", &eingabewert);
if(eingabewert < -1){
printf("A student can't have 0 > points.\n");
exit(0);
}
userMarks[counter] = eingabewert;
counter += 1;
}
printf("Please insert, the least pints needed for 6:");
//Second Scanf doesn't work, it stays in a Loop or something like that
scanf(" %d", &maxnote);
for(int i = 0; userMarks[i] != -1; i++){
userMarks[i] = berechneNote(userMarks[i], maxnote);
}
countMarks(userMarks);
notenstats(userMarks);
promark = ((suffmark/counter) * 100);
printStatistic(maxnote, promark);
}
The first Scanf() does it job perfectly and takes the given numbers.
However the second one isn't doing that.
It stays in a Loop and I can't go forward with my code.
What should I do to fix this?
Because you are using eingabewert uninitialized in
while (eingabewert != -1){
Initialize it with
int eingabewert = 0;
And always check the result of scanf
while ((eingabewert != -1) && (scanf("%d", &eingabewert) == 1))
You are also using userMarks uninitialized in
for(int i = 0; userMarks[i] != -1; i++){
In this case (an array) initialize it using
int userMarks[200] = {0};
There is a space in the format specifier in the second scanf. And you should learn how to use a debugger, like gdb. It's a lot faster than posting such a long question on SO.
Related
I have been working on a hangman game for my class which is due today and just now it decided to no longer provide any output from my code. If someone could please give it a look so I can go back to possibly submitting this assignment, I would be very appreciative. I dont know what changed specifically.
char **readWordList(char *, int *);
int main(int argc, char *argv[]) {
char **wordList;
char inputFile[100];
int count = 0;
int i;
if (argc != 2) {
printf("You need to provide the word list file name.\n ");
printf("Usage: $0 filename\n");
return -1;
}
wordList = readWordList(argv[1], &count); //function (target input[s], y placeholder var)
if (wordList == NULL) {
printf("Read word failed\n");
exit(1);
}
printf("fortnite");
int a = 0; //placeholder variables
int b = 0;
int c = 0;
int v = 0;
int g = 0;
int hit = 0;
srand(time(NULL)); //random variable for word selection
int r = rand() % 3;
int chances = 10;
char *word = wordList[r]; //address word from line.txt
char guess;
char misses[10];
int lettercount = 0;
//make blank variable by reading random accessed word
for (size_t a = 0; word[a] != 0; a++) {
lettercount++;
}
char space[lettercount];
// write underscores in place of spaces in temporary array
for (size_t c = 0; word[c] != '\0'; c++) {
space[c] = 95;
}
char blank[lettercount * 2]; //equal to array size empty array
// borrowing my spacename function, but seems to make artifacts in blank input now
int t = 0;
int k = 0;
while (space[t] != '\0') {
k = 2 * t;
if (k > lettercount * 2 - 2) {
blank[k] = space[t];
break;
}
blank[k] = space[t];
blank[k + 1] = ' ';
}
while (chances > 0) {
printf("Chances:%d\n", chances);
printf("Misses:%d\n", misses);
printf("Word:%s\n", blank);
printf("Guess[Q]:");
scanf("%c\n", &guess);
while (word[b] != '\0') {
if (guess = 'Q') {
exit(0);
}
if (guess = word[b]) {
v = b * 2;
blank[v] = guess;
b++;
hit = 1;
}
b++;
}
if (hit != 1) {
misses[g] = guess;
}
if (hit = 1) {
hit = 0;
}
chances--;
g++;
}
}
There are multiple problems in the code, including some serious ones:
the #include lines are missing.
the readWordList function is missing.
if (guess = 'Q') sets guess to 'Q' and evaluates to true. You should write if (guess == 'Q')
if (guess = word[b])... same problem.
printf("Misses:%d\n", misses); should be printf("Misses:%s\n", misses); and misses should be initialized as the empty string.
printf("Word:%s\n", blank); has undefined behavior as blank is not null terminated.
while (space[t] != '\0') may iterate too far as space does not have a null terminator since it's length is lettercount and all elements have been set to 95 ('_' in ASCII). Yet since you never increment t, you actually have an infinite loop. Use a simple for loop instead: for (t = 0; i < lettercount; t++)
scanf("%c\n", &guess); reads a character and consumes any subsequent white space, so the user will have to type another non space character and a newline for scanf() to return. You should instead use scanf(" %c", &guess);
while (word[b] != '\0') will iterate beyond the end of the array after the first guess because you do not reset b to 0 before this loop. Furthermore, b is incremented twice in case of a hit. You should use for loops to avoid such silly mistakes.
if (hit = 1) { hit = 0; }... the test is incorrect (it should use ==) and you could just write hit = 0; or better set hit to 0 before the inner loop.
inputFile is unused.
You should compile with gcc -Wall -Wextra -Werror to avoid such silly bugs that can waste precious time.
i fixed it, i lost a variable which provided the chance that a while loop would end for the spacing array function
sorry for being annoying
I wrote a program that scans an unknown amount of integers into an array but when I run it, it print the last value it has gotten an infinite amount of times.
For example for the input: 1 2 3 4 5
The output would be 55555555555555555555555...
Why does this happen and how can I fix that?
My goal here is to create a array, for an instance {1, 2, 3, 4, 5} and then print what it scanned into the array, ONLY ONCE...
int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSet == NULL) {
return FAIL;
}
scanf("%d", &c);
pSet[i] = c;
printf("%d ", c);
}
free(pSet);
Why does this happen (?) (print ... an infinite amount of times.)
Look at the loop terminating conditions c != EOF.
int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) { // Not good code
scanf("%d", &c);
}
EOF is some negative value, often -1. scanf("%d", &c) attempts to read user input and convert to an int. scanf() returns a 1,0,EOF depending on if it 1) succeeded, 2) failed to find numeric text or 3) end-of-file or input error occurred. Unfortunately code does not use that return value. Instead code used the number read, c and checked if that number read was the same as EOF.
how can I fix that?
Only loop when the return value of scanf() is as expected (1).
for(i = 1; scanf("%d", &c) == 1; i++) {
...
}
Putting this together with some other ideas
#include <stdio.h>
#include <stdio.h>
int main(void) {
printf("Please enter a stream of numbers to make a set out of them:\n");
int *pSet = NULL; // Start with no allocation
size_t i = 0;
int c;
for (i = 0; scanf("%d", &c) == 1; i++) {
// +--------------------------- No cast needed.
// v v----------v Use sizeof de-referenced pointer
void *p = realloc(pSet, sizeof *pSet * (i + 1));
if (p == NULL) {
free(pSet);
return EXIT_FAILURE;
}
pSet = p;
pSet[i] = c;
}
for (size_t j = 0; j < i; j++) {
printf("%d ", pSet[j]);
}
free(pSet);
return 0;
}
There are a number of problems.
1) Terminate the loop when scanf fails instead of using EOF. Do that by checking that the return value is 1 (i.e. the number of input items
successfully matched)
2) Don't allocate memory until it's needed
3) Never do realloc directly into the target pointer - always use a temp variable.
Fixing this your code could be:
#include <stdio.h>
int main(void) {
int *pSet = NULL;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
int i = 0;
int c;
while (1) {
if (scanf("%d", &c) != 1)
{
printf("Terminating input loop\n");
break;
}
int* tmp = realloc(pSet, sizeof(int)*(i+1));
if(tmp == NULL) {
printf("oh dear...\n");
break;
}
pSet = tmp;
pSet[i++] = c;
printf("%d ", c);
}
for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
free(pSet);
return 0;
}
Input:
1 2 3 4 5 6 7 stop
Output:
Please enter a stream of numbers to make a set out of them:
1 2 3 4 5 6 7
Terminating input loop
1
2
3
4
5
6
7
You should stop your loop when scanf fails. According to the manual:
On success, [scanf] return[s] the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs. [...]
So you can turn your for loop into a while one.
#include <stdio.h>
#include <stdlib.h>
#define FAIL 0
int main() {
int *pSet = (int*) malloc(sizeof(int));
int c;
int i=0;
printf("Please enter a stream of numbers to make a set out of them: ");
while(scanf("%d", &c) == 1) {
pSet[i] = c;
pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSetNew == NULL) {
free(pSet);
return FAIL;
} else {
pSet = pSetNew;
}
printf("%d ", c);
i++;
}
free(pSet);
}
But if you want a more robust piece of code, I suggest you to retrieve the answer as a string (NULL-terminated array of char), and then parse it with dedicated functions like strtol which let you check if the whole string is a valid entry, and not only the first characters.
Note: HengLi fixed a potential memory leak in the code sample above
`
void avgOfArray()
{
float avg = 0, *ptr = 0;
ptr = (float*)malloc(5*sizeof(float));
printf("Enter 5 numbers: \n");
for(int x = 0; x < 5; x++) {
ptr[x] = getchar();
while ((ptr[x] = getchar()) != EOF && ptr[x] != '\n');
}
for (int y = 0; y < 5; y++) {
avg = avg + ptr[y];
}
avg = avg / 5;
printf("Average = %0.2f \n", avg);
system("pause");
}
`
I'm learning about pointers in class and the question asked to get the average of 5 numbers. Every output is 10 regardless of the input. If someone could explain the issue that would be very appreciated.
getchar returns the code of the character, not the float itself.
Since your loop scans the chars until it meets \n (ASCII code = 10), you always get 10 (as float).
Don't rewrite float scan, use fgets to get a line (issue with end of file or \n automatically handled), then scan 5 floats from the line buffer, or use scanf 5 times with a space
int i;
for (i=0;i<5;i++)
{
scanf(" %f",p+i); // no error check!
}
Don't cast malloc, and also check the return value of malloc, if it
returns NULL, you cannot access the memory otherwise it's undefined behaviour.
float *ptr = malloc(5 * sizeof *ptr);
if(ptr == NULL)
{
fprintf(stderr, "Not enough memory\n");
return; // or exit or whatever
}
Also note that dynamically allocating space is usually needed when the size is
not known at compile time, because the user inputs the size or it has to be
calculated. In your example you already know the size, malloc is not needed.
float arr[5]; would be enough.
getchar(); returns a single character. The value of the character is
determined by the ASCII table. The value for '1' is not the same as the
value 1, because '1' is 49. You have to read all the characters forming a
number and then convert them to float using functions like scanf or strtof.
Alternative 1: using scanf.
// assuming you are using ptr = malloc(...)
for(size_t i = 0; i < 5; ++i)
{
while(scanf("%f", ptr + i) != 1)
{
// clear buffer
int c;
while((c = getchar()) != '\n' && c!= EOF));
if(c == EOF)
{
// cannot continue doing scanf
free(ptr);
return; // or exit
}
printf("Please re-enter the number:\n");
}
}
Alternative 2: using fgets
char line[50];
for(size_t i = 0; i < 5; ++i)
{
while(1) // continue reading if value is not a float
{
if(fgets(line, sizeof line, stdin) == NULL)
{
// cannot continue reading
free(ptr);
return; // or exit
}
char *end;
float val = strtof(line, &end);
if(*end == '\n' || *end == '\0')
{
ptr[i] = val;
break; // exit while(1) loop, continue reading next value
} else
printf("Please re-enter the number:\n");
}
}
Also at the end do not forget to free the memory with free(ptr);.
Let's say I am creating a 3*4 matrix (or a 2D array of 12 elements). So I want user to enter values of elements one by one as a sequence, divided by either spaces/tabs or enter-key. Also, if a value in a sequence is bad (in my case, any non-integer values are bad), I want to ignore it and read next values until I have all 12 of them.
int fill(Matrix * mtx)
{
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0;
for (int i = 1; i <= mtx -> rows; i++)
{
for (int j = 1; j <= mtx -> cols; j++)
{
scanf(" %d", &temp);
setElement(mtx, i, j, temp);
}
}
return 0;
}
This is my most basic vision of the algorithm; I was wondering about the implementation of this "skip input if bad" condition.
Just started learning C btw, so any kind of advice is hugely appreciated!
You have to check the return value of scanf to be sure whether it scanned the integer input correctly or not. In case it fails due to some bad input - scanf can't take that as input and then you have to make sure that you clear the stdin so that the next calls of scanf don't fail. What you can do is, when scanf returns 0 - consume all characters (using getchar or similar) and do this until you get \n (Considering that user inputs the number each in a line). Illustration would be:
int n; //total number inputs to take.
n = 10;
int num, num_inputs = 0;
while( 1 )
{
while(scanf("%d", &num) != 1)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
if(c == EOF){ fprintf(stderr,"Error in input\n"); exit(1)}
}
num_inputs++; // one more int correctly input.
...
if( num_inputs == n )
break;
}
An alternative and better way would be to use strto* functions and then considering the return value of it to understand whether there is any error or not. Illustration would be: (Here we have shown just the case where there is single int input in each line - this can be extended to process multiple int inputs in a line).
char buf[MAXLEN];
int num_inputs = 0;
while(fgets(buf,MAXLEN,stdin)){
char *en;
errno = 0;
long n = strtol(line, &en, 10);
if (errno == 0 && *en== '\0' && n >= INT_MIN && n < INT_MAX)
{
// n is an correctly inputted int
num_inputs++;
}
}
Check the man page for strtol - there is a detailed listing of the erros one might get. Check it.
Check what scanf returns. If not 1 means entered value is not a digit in this case. So discard the data from the stream first before entering next data.
int fill(Matrix * mtx) {
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0, v;
for (int i = 1; i <= mtx->rows; i++) {
for (int j = 1; j <= mtx->cols; j++) {
v = scanf(" %d", &temp);
if (v != 1) { //if invalid input.
while ( (v = getchar()) != EOF && v != '\n' ); // discard invalid input.
j--; //don't forget to `j--` or else you will skip one position.
}
else { // if correct input.
setElement(mtx, i, j, temp);
}
}
}
return 0;
}
I am taking input in an array of length 100 using scanf in a loop. After 20 numbers, if I enter -1, I want the loop to exit, i.e finish taking input and continue with the rest of the program. I am doing something like this
for(i=0;i<100;i++)
{
scanf("%d", &input[i]);
if(input[i] == -1)
{
break;
}
}
I heard, it is bad practice to use break statements even though this code works perfectly fine. So I was wondering what is a more efficient way to end the loop when -1 is entered. I tried
for(i=0;scanf("%d",&input[i])!=-1;i++)
also
fori(i=0;i<100;i++){
do
{scanf("%d", &input[i]);
}while(input[i]!=-1
}
Neither of these don't work
The second expression of the for loop is a free-form boolean expression. In this case you could add your condition there. However in this case it wouldn't look exactly nice. For example
for(i=0; i < 100 && (i < 1 || input[i - 1] != -1); i++)
{
scanf("%d", &input[i]);
}
I.e. if we have already input one value, check the value and that must be inequal to -1 for the loop to continue
Another would be to use a synthetic flag variable:
int loop_again = 1;
for (i = 0; loop_again && i < 100; i++) {
scanf("%d", &input[i]);
if(input[i] == -1)
{
loop_again = 0;
}
}
All in all, these both look way uglier than just using the break statement for the very thing that it was invented for.
Note that you also should check the return value of scanf itself!
it is bad practice to use break statements
As Ancient Greeks said, "Pan Metron Ariston", which means that everything that is used with balance is great. This applies here too, and your code as is, is good to go. The only thing to be worried about is not checking the return value of scanf().
Now if you really insist on changing your approach, then please refer to Haapala's answer, we got there first.
You can use a while loop and check for -1 in the input in the loop conditional. Note that you should always check the value returned by scanf(). In the posted code, non-numeric input results in no value being stored in input[]; this may lead to undefined behavior later if the code attempts to use an indeterminate value.
Here is an example. Note that the loop conditional first checks whether the array index has grown too large, then checks the return value from scanf() to be sure that a number was entered, then checks to see if -1 was entered. In the case of non-numeric input, the loop is terminated.
#include <stdio.h>
#define INPUT_SZ 100
int main(void)
{
int input[INPUT_SZ];
size_t i = 0;
while (i < INPUT_SZ && scanf("%d", &input[i]) == 1 && input[i] != -1) {
++i;
}
puts("You entered:");
for (size_t j = 0; j < i; j++) {
printf("%d\n", input[j]);
}
return 0;
}
Sample interaction:
2 4 6 8 -1
You entered:
2
4
6
8
You can simply change the value of counter variable to max, then it'll automatically come out of loop.
#include<stdio.h>
#define MAX 10
int main()
{
int ar[MAX], i, count;
for(i=0; i<MAX; i++)
{
scanf("%d", &ar[i]);
if(ar[i]==-1)
{
count=i--; //this is your new MAX. Not mandatory but will be useful if you need to access array elements
i=MAX;
}
}
//printing array
for(i=0; i<count; i++)
{
printf("Element %d: %d\t", i+1, ar[i]);
}
return 0;
}
Hope this helps.
Use a do-while loop
int i=0;
do{
if(scanf("%d", &input[i++]) != 1)
{
if(i>0)
--i; // Decrementing i if an integer is not provided
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) // Wasting the buffer
;
}
}while(input[i-1] != -1 && i<=99);