I'm trying to take the input of floating numbers from a file and arrange it into an array.
The only trouble is that I don't know exactly how many floating numbers there will be each time though I do know that the max amount of floating numbers is 1000.
What I need to do is have fscanf take all the floating numbers but then stop at the next line, which is full of integers.
Here is what I have so far for this section:
for (repetition = 0; repetition <= 1000; repetition++)
{
fscanf(userFile, "%f", &itemPrice[itemNumber]);
itemNumber++;
}
But unfortunately, this continues on to assign array values to all of the other values in the next several lines.
I found another user input, auctionItems and used that to control the array length using while(itemNumber < auctionItems)
The return value of fscanf is the number of items successfully read. Use that to decide when to stop.
#include <stdio.h>
int main(int argc,char * argv[])
{
int i;
float ff[1000];
char next_text[17];
for (i=0; i < 1000; i++) {
int n_read;
n_read = fscanf(stdin, " %f", &( ff[i] ));
if (n_read < 1) {
fscanf(stdin, "%16s", next_text);
next_text[16] = (char) 0;
printf("Next text: '%s'\n", next_text);
break;
}
}
printf("Read %d items, %f .. %f\n",i,ff[0],ff[i-1]);
return 0;
}
Maybe you could try this method using fgetc and fputc:
for (repetition = 0; itemPrice <= 1000; repetition++)
{
int c = fgetc(userFile);
if (c == '\n' || c == EOF) break;
fputc(c);
fscanf(userFile, "%f", &itemPrice[itemNumber]);
itemNumber++;
}
char input[MAX];
while(fgets(input, MAX, userFile) != NULL){
sscanf(input, "%lf", &itemPrice[itemNumber++]);
}
OP is fairly close. Just stop when scanning fails.
fscanf() returns the number of fields scanned or EOF. In this case, checking for 1 is sufficient.
// for (repetition = 0; itemPrice <= 1000; repetition++) Use <, not <= #Arpit
for (i = 0; i < 1000; )
{
int retval = fscanf(userFile, "%f", &itemPrice[i]);
if (retval != 1) break;
i++;
}
A robust solution would detect unexpected data. This solution simple goes until the end-of-file or non-float text is encountered.
[Edit]
It appears OP has only 1 line of floats. In that case code could read the whole line and then parse the buffer.
#define CHAR_PER_FLOAT_MAX 20
char buf[1000*(CHAR_PER_FLOAT_MAX + 1)]; // Some large buffer
if (fgets(buf, sizeof buf, input)== NULL) return; // EOF or IO error
char *p = buf;
for (i = 0; i < 1000; ) {
int n = 0;
if (sscanf(p, "%f %n", &itemPrice[i], &n) != 1) break;
p += n;
i++;
}
if (*p) Handle_ExtraTextOnLine();
foo(itemPrice, i); // Use data
Another approach is to read direct from the file 1 float at a time and then look at the following white-space for an end-of-line. Less elegant.
for (i = 0; i < 1000; ) {
if (fscanf(input, "%f", &itemPrice[i]) != 1) {
// need to add code to consume the rest of the line if processing is to continue.
break;
}
i++;
// look for standard white-space
char buf[2];
while (fscanf(input, "%1[ \f\n\r\t\v]", buf) == 1) {
if (buf[0] == '\n') break;
}
}
foo(itemPrice, i); // Use data
Related
`
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;
}
Currently I am reading file, and printing (stdout) all words/strings that it contains.
Here is the code:
int scan_strings(FILE *in, FILE *out)
{
char buffer[64];
int i = 0, n = 0;
for(;;)
{
if (fscanf(in, "%*[^" charset "]") != EOF)
{
i = 0;
while (fscanf(in, "%63[" charset "]%n", buffer, &n) == 1)
{
if (n < 4 && i == 0)
{
break;
}
else
{
i = 1;
}
fputs(buffer, out);
}
if (i != 0)
{
putc('\n', out);
}
}
if (feof(in))
{
return 0;
}
if (ferror(in) || ferror(out))
{
return -1;
}
}
}
But what I am trying to do, is to search the strings from a buffer which is already read to memory.
I changed in and out variables to unsigned char* and changed fscanf to sscanf. That however doesn't work. Am I misunderstanding the sscanf function, or is there something else wrong in my code?
How I can print all strings from already-read buffer? The data is binary data.
I am working on Windows and Linux portability isn't needed.
sscanf(data, "%*[^" charset "]") works differently from fscanf(in, "%*[^" charset "]"). when data is binary.
Assume charset is some string like "123".
fscanf(in, "%*[^123]") will scan in as long as the char read is not '1', '2', or '3'.
This includes '\0'.
sscanf(data, "%*[^123]") will scan data as long as the char read is not '1', '2', or '3'.
This does not include '\0' as sscanf quits offering char to scan once '\0' is encountered.
Using sscanf() to scan over '\0' is not possible.
[Edit]
OP: How should I go about doing it - for binary data(from buffer/variable)?
A: Additional code around sscanf() can be used to cope with its stopping a scan when '\0' is encountered. Something like just for the first sscanf():
size_t j=0;
for (;;) {
// if (fscanf(in, "%*[^" charset "]") != EOF)
while (j < datasize) {
int n = 0;
sscanf(&data[j], "%*[^123]%n", &n);
if (n > 0) j += n;
else if (data[j] == '\0') j++;
else break;
}
if (j < datasize) {
i = 0;
...
As you can see things are getting ugly.
Let's try using strchr() with untested code:
size_t j=0;
for (;;) {
while (j < datasize) {
int ch = data[j];
if (ch && strchr(charset, ch) != NULL) break;
j++;
}
if (j < datasize) {
i = 0;
...
Getting better and this is only for the first sscanf().
The problem is that your code never modifies in. When in is a file fscanf will move through it sequentially. But sscanf doesn't work that way.
You need to find out how many characters sscanf read, and then increment in accordingly.
You're already getting the number of bytes read in n, so just add that to in.
in += n;
... after the sscanf.
everyone!
I hope someone can help me figure out something in C language.
This is my first seriously homework in IT, I have no experience and I'm learning in e-studies, so teacher help isn't very available.
I need to develop console application in C language. User need to input 10 integer numbers, if insert number isn't integer, need to output error and again re-enter new number until all 10 integer numbers will be inserted.
Everything works in case if I say that these 10 numbers can't be 0 (I make this to be sure that my if-else statement working), but won't work when I want that every input number will be check if it is integer or not.
How can I do it right.
Please help
so far my code look like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
float f;
int numbers[10];
for (i = 0; i < 10; i++)
{
scanf ("%d", &numbers[i]);
if (numbers[i] != 0)
{
scanf ("*%d", &numbers[i]);
}
else
{
printf ("\nError!Entered number is't integer \n");
printf ("\nPlease insert number again \n");
scanf("%*d", &numbers[i]);
}
}
}
#include <stdio.h>
int main(void) {
int i = 0;
int val;
char ch;
int numbers[10];
while(i < 10) {
val = scanf("%d", numbers + i); // read the integer into a[i]
if(val != 1) {
while((ch = getchar()) != '\n') // discard the invalid input
; // the null statement
printf("Error! Entered number is not an integer.\n");
printf("Please enter an integer again.\n");
val = scanf("%d", numbers + i);
continue;
}
++i;
}
// process the numbers array
return 0;
}
I write this line again
val = scanf("%d", numbers + i);
Now it works how I need. Great - thanks a lot
There are several techniques you might use:
Read the number as a string and reject if it contains characters not suitable for an integer. The use sscanf() to convert the string to integer.
Read the number as a float and reject if it is out of integer range or it has a non-integer value.
Read the input character by character and build up an integer value. If invalid characters appear, reject the value.
scanf returns the number of input items successfully matched and assigned. You can check this value for 1 for each call of scanf. If the value is 0, then you should discard the input to clear the stdin buffer and read input again.
#include <stdio.h>
#include <ctype.h>
int main(void) {
int i = 0;
int val;
char ch;
int numbers[10];
while(i < 10) {
// read an integer and the first non-numeric character
val = scanf("%d%c", numbers + i, &ch);
// if the number of items assigned by scanf is not 2 or if
// the first non-numeric character is not a whitespace, then
// discard the input and call read input again.
// for example input of type 32ws are completely discarded
if(val != 2 || !isspace(ch)) {
while((ch = getchar()) != '\n') // discard the invalid input
; // the null statement
printf("Error! Entered number is not an integer.\n");
printf("Please enter an integer again.\n");
continue;
}
++i;
}
// process the numbers array
return 0;
}
Although I am not entirely clear on the details of your question, here is an outline of code similar to what you want:
int main(void)
{
int i;
int numbers[10];
int sum = 0;
for(i=0; i<10; ++i)
{
printf("Enter #%d:\n", i+1);
scanf("%d", numbers+i);
if (numbers[i] % 2 == 0) // Then Number is even
{
sum += numbers[i];
}
}
printf("The sum of only the even numbers is %d\n", sum);
getch();
return 0;
}
To read an int, suggest fgets() then sscanf() or strtol()
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
int numbers[10];
for (i = 0; i < 10; ) {
char buffer[50];
if (fgets(buffer, sizeof buffer, stdin) == NULL) break;
int n; // number of `char` parsed
if (sscanf(buffer, "%d %n", &numbers[i], &n) != 1 || buffer[n] != '\0') {
printf("Error! Entered number is not an integer.\n");
printf("Please enter an integer again.\n");
continue;
}
i++;
}
return 0;
}
The strtol() approach. This detects overflow issues:
if (fgets(buffer, sizeof buffer, stdin) == NULL) break;
char *endptr;
errno = 0;
long num = strtol(buffer, &endptr, 10);
if (errno || num < INT_MIN || num > INT_MAX) Handle_RangeError();
if (buffer == endptr || *endptr != '\n') Handle_SyntaxError();
numbers[i] = (int) num;
Recommend making a int GetInt(const char *prompt) function that can be used repeatedly.
User input is evil. Do not trust it until well vetted.
I am trying to read in an equation, then take each part separately, however then user can enter as big or small equation as they like (for example. 3+7, 2+-9+8 or even 2). I have this however it doesn't seem to be working.
printf("Please enter an equation\n");
scanf("%f", &num);
//printf("%f", num);
while ( num != '\n'){
scanf("%f", &num);
scanf("%c", &op);
//printf("%c %f \n", op, num);
}
when i output what i have got it is not the same as the input.
You may wish to read How to read a line from the console in C? for the full details, but basically you just do this:
char * getline(void) {
char * line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if(line == NULL)
return NULL;
for(;;) {
c = fgetc(stdin);
if(c == EOF)
break;
if(--len == 0) {
len = lenmax;
char * linen = realloc(linep, lenmax *= 2);
if(linen == NULL) {
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
You are trying to take the complete expression in a float variable (num, in your code). If you do a scanf("%f", &num); in while loop then you are just overwriting the values in num. You need to take the expression in a char array or char*. Then you need to have an algrithm to seperate the operators and numbers, convert the numbers to desired type and solve the euation.
If you want to read an expression and have your program understand that, you need severely heavier machinery. Either this is an XY problem, i.e., you need to rethink the problem and find another approach; or you should look into the whole parsing/compiling area.
Scripting languages (like Python or Perl) have some sort of eval builtin, so you can take a snippet of code as text and get it evaluated (run). Perhaps using one of those is a better match to your problem? But take care, blindly running anything the user inputs is a huge risk...
To read an arbitrary-length line with scanf, you can use
scanf("%[^\n]", equation);
This regular expression means "read everything until you find the '\n' character".
Keep in mind that this is not secure though, since the user can easily overflow the "equation" buffer. If you want to avoid that, I would suggest reading char by char in a loop, like so:
for(i=0; i < MAX_EQ_SIZE; i++)
{
char tmp;
scanf("%c", &tmp);
if(tmp == '\n')
break;
equation[i] = tmp;
}
Since you are asking just how to read, I'm not going into parsing the read equation.
Here is a code example:
#include <stdio.h>
#define MAX_EQ_SIZE 1024
void parse(char * eq)
{
// Do the processing
}
int main()
{
char equation[MAX_EQ_SIZE];
scanf("%[^\n]", equation); // Read a whole line
scanf("%*c"); // Read and ignore the \n
puts(equation);
parse(equation);
}
Use fgets() to read the line of input.
Use the return value from sscanf() to determine if number or operator.
int Eval(void) {
char buffer[100];
char *p = buffer;
printf("Please enter an equation\n");
if (fgets(buffer, sizeof buffer, stdin) == NULL)
return -1; // no more input
float num;
char op;
int n;
while (*p) {
if (sscanf(p, "%f %n", &num, &n) == 1) {
printf("num %f\n", num);
p += n;
}
if (sscanf(p, " %c %n", &op, &n) == 1) {
printf("op %c\n", op);
p += n;
} else if (*p) {
printf("Error '%s'\n", p);
return 0;
}
}
return 1;
}