How to use fscanf to read doubles in C [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I am currently writing a program that takes in an unknown number of doubles, each on their own line from a text file. It should be placing of these elements read into an array, but it isn't working. My print loop works, but it only prints zeroes. I've tried a lot of things and looked up a lot before coming here. This is my code.
#include <stdio.h>
#include <stdlib.h>
int main()
{
//Open an file to read from
FILE *file;
file = fopen("data.txt","r");
if (file == NULL)
{
printf("File not found.");
return -1;
}
//Count the number of lines in the input file
int numLines = 0; //CHANGE TO 1 ???
int ch;
do
{
ch = fgetc(file);
if (ch == '\n')
numLines++;
} while (ch != EOF);
//Put all of the data read into an array;
double input[numLines];
int i = 0;
while ((fscanf(file, "%lf\n", &input[i])) == 1)
i++;
//Close the file
fclose(file);
//Test printing elements of array
for (i = 0; i < numLines; i++)
printf("%lf\n", input[i]);
return 0;
}

OP's test of fscanf() result is good, except code did not also check if too many numbers were in the file.
while ((fscanf(file, "%lf\n", &input[i])) == 1)
i++;
Then code ignored that last value of i and instead printed numLines times, even if fewer were successfully scanned.
for (i = 0; i < numLines; i++)
printf("%lf\n", input[i]);
End code should have been
while (i < numLines && (fscanf(file, "%lf\n", &input[i])) == 1)
i++;
for (j = 0; j < i; j++)
printf("%lf\n", input[j]);
This would have printed 0 lines! The file needed to be reset for a second pass. #paulr
rewind(file);
while (i < numLines && (fscanf(file, "%lf\n", &input[i])) == 1)
...
A further problem is assuming the count of '\n' is the same as the count of numbers. This can easily be fooled given multiple numbers per line or the last line having a number yet no '\n'.
A simple work-around it to make the input[] 1 larger and use the actual scan success count as the count of numbers to print. More robust code would read 1 line at a time with fgets() and include additional error checks.

Related

Segmentation Fault 11 using nested loops with arrays

I'm not sure why I'm receiving this error. I was wondering could it be due to my terminal not being able to read the txt files that run with this program. Let me know if that could be a possible reason for that message.
Im mainly just looking for syntax errors. The files I have just contain a big bunch of numbers and I'm supposed to work from the third value onwards {the first two have another use)
#include <stdlib.h>
#define N 1000000
int main(void)
{
int n; /* The number of lengths */
int x; /* The target length */
int lengths[N]; /* The array of available lengths */
int i, j;
int whichfile=1;
FILE *fp;
scanf("%d", &whichfile);
switch (whichfile) {
case 1:
fp = fopen("testcase_small_sorted.txt", "r");
break;
case 2:
fp = fopen("testcase_large_sorted.txt", "r");
break;
case 3:
fp = fopen("testcase_small_nomatch_sorted.txt","r");
break;
case 4:
fp = fopen("hidden_small_sorted.txt","r");
break;
case 5:
fp = fopen("hidden_large_sorted.txt","r");
break;
}
fscanf(fp, "%d", &x);
fscanf(fp, "%d", &n);
for (i=0;i<n;i++)
fscanf(fp, "%d", &lengths[i]);
fclose(fp);
/* Now all the input data has been read in
search for the required pair of lengths... */
x = lengths[0];
n = lengths[1];
for(i = 2; i < n; i++)
{
for(j = 2; i < n; j++)
{
if(lengths[i] + lengths[j] == x)
{
printf("Found: %d + %d == %d\n", lengths[i], lengths[j], x);
}
}
}
return 0;
} ```
I'm mainly just looking for syntax errors.
Syntax errors are only the beginning. C will not check anything for you. You have to check if files opened, if input scans worked, if values are inside array bounds. If you don't, that's how you get segfaults.
For files, the usual pattern is to try to open the file, check its return value, and then handle the error. fopen returns NULL on error and sets errno. errno is a global which holds what sort of error happened like "file not found", but it's a number. strerror is handy to turn it into an error message. Finally fprintf is like printf but can print to things other than stdout. In this case stderr. Both stdout and stderr normally appear on the screen, but they can be separated.
FILE *fp = fopen(path, mode);
if( fp == NULL ) {
// This will print something like "Could not open testcase_small_sorted.txt: No such file or directory"
fprintf(stderr, "Could not open file %s: %s", path, strerror(errno));
exit(1);
}
But now we need to copy this five times because the code repeats fopen. Instead of each case opening the file, what if it just picked a filename? And since each filename has a number, what if they were just in an array?
const char *files[] = {
NULL, // 0 is not used
"testcase_small_sorted.txt",
"testcase_large_sorted.txt",
"testcase_small_nomatch_sorted.txt",
"hidden_small_sorted.txt",
"hidden_large_sorted.txt"
};
const char *path = files[whichfile];
What if they input something that's not a number? Or what if the number is out of range? These need to be checked for as well. scanf will return the number of items matched. We expect 1. If we get anything else it didn't work.
// Check that we read an integer.
if( scanf("%d", &whichfile) != 1 ) {
fprintf(stderr, "Please enter 1-5.\n");
exit(1);
}
// Check that it's in range.
if( (whichfile < 1) || (5 < whichfile) ) {
fprintf(stderr, "Please enter 1-5.\n");
exit(1);
}
Note that scanf has a lot of problems and should be swiftly discarded once you learn things like fgets and sscanf.
int lengths[1000000] is 4 to 8 megabytes (1 million integers at 4 or likely 8 bytes per integer) and might get you an eponymous stack overflow. Your algorithm is O(n^2) which means if there really were 1,000,000 items it would take 1,000,000,000,000 iterations to find all the pairings and your class will probably be done before the program is.
(A little hint to improve the algorithm: if the numbers are sorted, and you're looking for two of them to sum X, do you need to check every number?)
I think you're meant trust n from the file for how many to read. Normally you don't have this, it's a crutch to let you read input without using dynamic memory (you'll be taught that later). Even if you had it, you wouldn't trust it anyway in production code; if it lies you'll walk out of your array bounds. But for this exercise that's fine.
// Read the first two lines, the sum and the number of remaining lines.
// Note that `fscanf` can also fail and needs to be error checked.
// I'll leave that as an exercise.
fscanf(fp, "%d", &x);
fscanf(fp, "%d", &n);
// Use `n` to allocate just enough space on the stack.
int lengths[n];
// Read the rest.
// Use braces, even for one line.
// They avoid a very silly and hard to debug mistake.
for (i=0;i<n;i++) {
fscanf(fp, "%d", &lengths[i]);
}
fclose(fp);
There's no need to put x and n into lengths. They aren't meant to be summed and you skip over them anyway by starting your loops at 2.
With that fixed the loops can start at 0. There is a mistake in the inner loop, it should check j < n not i < n.
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++) // <<--- j < n, not i < n.
{
if(lengths[i] + lengths[j] == x)
{
printf("Found: %d + %d == %d\n", lengths[i], lengths[j], x);
}
}
}

How do I a split a line of integers into array? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
If a user inputted:
1 2 3 4 5 0
How would I transform it into an array with 5 elements (The 0 integer indicates termination)? Also, in the code I need to ensure it works for up to 500 integers.
I have no clue how to proceed. I am thinking of using gets and saving it into an allocated space:
char *ptr;
ptr = malloc(sizeof(char) * 1000);
fgets(ptr, sizeof(char)*1000, stdin);
The problem here is I am not sure how to allocate the space as each digit will be saved as a character and each integer may have different number of digits.
Afterwards, I am not sure how to split it into array.
Could someone advise me on how to continue or if my method is not good?
I know I have not done a lot but I am really confused. I have looked up on gets(), fgets(), scanf(), fscanf(), and am still not sure.
Thanks!
You can parse the line input by the user with sscanf() or strtol():
#include <stdio.h>
int main() {
char buf[256];
int array[5];
if (fgets(buf, sizeof buf, stdin)) {
if (sscanf(buf, "%d%d%d%d%d", &array[0], &array[1], &array[2], &array[3], &array[4]) == 5) {
// array has the 5 numbers input by the user.
printf("%d %d %d %d %d\n", array[0], array[1], array[2], array[3], array[4]);
}
}
return 0;
}
For generic code that works up to 500 numbers, you can just use scanf() in a loop:
#include <stdio.h>
int main() {
int array[500];
int i, n;
for (n = 0; n < 500; n++) {
if (scanf("%d", &array[n]) != 1) {
printf("invalid input\n");
return 1;
}
if (array[n] == 0) {
// 0 indicates termination
break;
}
}
// the array has n valid non-zero numbers
printf("The numbers are:\n");
for (i = 0; i < n; i++) {
printf(" %d\n", array[i]);
}
return 0;
}
You could use a character array with a combination of fgets() and strtok().
First declare a character array str and set a flag variable.
char str[100];
int flag=1;
flag may be made 0 when input 0 is found.
As long as flag is 1 use fgets() to read a line of input (provided fgets() is successful) as in
while(flag==1 && fgets(str, sizeof(str), stdin)!=NULL)
{
.....
.....
}
Now inside this loop, use strtok() to tokenize the string in str using space and \n as delimiters. \n is made a delimiter because fgets() reads in the trailing \n to str as well.
for(ptr=strtok(str, " \n"); ptr!=NULL; ptr=strtok(NULL, " \n"))
{
n=atoi(ptr);
if(n==0)
{
flag=0;
break;
}
printf("\n%d", n);
}
Convert the tokens produced by strtok() to integers. I used atoi() for brevity but it is not the best way. strtol() might be a good idea. See here.
I would suggest something like this
#include "rlutil.h" //a good library similar to conio.h or it's Linux equivalent but cross-platform. You have to include it manually and download it at github.
int i = 0;
int num = 1;
char input;
int array[255];
for (i = 0; num = 0; i++)
{
input = getchar();
num = input - '0';
array[i] = num;
printf("%i ", num);
}
Just pay attention to the size of the array.
Furthermore you could parse the string you got with fgets with strtok. If you want I can edit this post later and include this variant.

Printf prints more character than those contained in my string [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have to write a program that acts like a shell. I wrote the function that gets the input from the user. I also wrote the function that splits it into arguments. The first time I type something, it works well, but the second time, it prints different characters after the ones that I gave it. I don't have to print it in the program. I was just doing it to see if it works correctly. I read a bunch of stuff online, but I can't figure out my error. I suppose it is in makeArgs(), but I can't pinpoint it.
Also, when I give it an input, the readline function adds a \n at the end of the string. I suppose it is from the fact that I press the enter key. I managed to solve the issue, by manually replacing it, but I would like to know if it is normal.
Any help really be appreciated.
Thank You
Screenshot of Xterm after 2 inputs.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getText();
int makeArgs();
char *textEntre;
size_t nbCharacters;
char **arguments;
int main (void)
{
while (1){
getText();
int nbArguments = makeArgs();
for(int i =0; i<5; i++){
printf("%s \n",arguments[i]);
}
for(int i=0; i<nbArguments; i++){//free the char ptrs at the end
free(arguments[i]);
}
}
free(textEntre);
free(arguments);
return 0;
}
int getText(){
size_t buffersize = 0;
nbCharacters = getline(&textEntre, &buffersize, stdin);
textEntre[nbCharacters-1] =' '; // when I press enter it regiter the enter as \n so I replace it with a space
return 0;
}
int makeArgs(){
arguments = (char **)malloc(sizeof(char*)*20);
int i;
int j = 0;
int k = 0;
int nbElem = 20; //the number of ptrs that can be in arguments
for(i = 0; i<nbCharacters; i++){
if(i == 20){ //increases the memory allocated if there are more than 20 arguments
nbElem = nbElem *2;
arguments = (char **)realloc(arguments, sizeof(char*)*nbElem);
}
if(textEntre[i] == '"'){ //checks for ""
i++;
while(textEntre[i] != '"'){
i++;
}
}
if(textEntre[i] == ' ' && textEntre[i-1] == ' '){ // eliminates useless spaces
j++;
}
else if(textEntre[i] == ' '){ //save a single argument
char * chptr;
chptr = (char *)malloc(i-j+1); //giving +1 for the \0 at the end
strncpy(chptr, &textEntre[j], i-j);
arguments[k] = chptr;
k++;
j = i +1;
}
}
return k;
}
chptr = (char *)malloc(i-j+1); //giving +1 for the \0 at the end
You properly allocated memory for that terminating \0, but where do you actually add that "\0 at the end"?
strncpy(chptr, &textEntre[j], i-j);
strncpy does not necessarily zero-terminate the destination buffer. You have to do it yourself.
In fact, in this specific application strncpy is a rather inappropriate function: it does not give you anything over ordinary memcpy and might be less efficient. You could just do
memcpy(chptr, &textEntre[j], i - j);
with potentially better efficiency. And, again, don't forget to zero-terminate the destination buffer.
Or you can use sprintf for the same purpose as follows
sprintf(chptr, "%.*s", i - j, &textEntre[j]);
which will produce a properly zero-terminated string in the destination. (Albeit you won't see sprintf used that way very often.)

How to increase array size that has global pointer in each loop [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I want to set the size of an array as the first integer in a text file (say 5). If I saved all the 5 integers that follow the size into the array, and there is still lines in the input file, I need to increase the size of the array each time and store that line (integer) in the array.
I wrote this code:
int *x;
int *sizeP;
int main(int argc, char *argv[]) {
int decision;
FILE* file = fopen( argv[1], "r" );
int size;
fscanf(file, "%d", &size);
sizeP = &size;
x=malloc(size*sizeof(int));
int p=0;
int num;
while(fscanf(file, "%d", &num) ) {
x[p] = num;
p++;
if (p >= size) {
puts("Enter 0 to continue or 1 to terminate");
scanf("%d", &decision);
break;
}
}
if (decision == 0){
while(fscanf(file, "%d", &num) ) {
size++;
x = (int*)realloc(x, size*sizeof(int));
x[p] = num;
p++;
}
free(x);
}
}
I am not sure what is wrong with this code?
Thank you in advance.
Your way of checking the result of fscanf is not correct. When the end of file is reached, fscanf does not return 0, but EOF, which is not zero (it is defined as -1 on most platforms).
while(fscanf(file, "%d", &num) )
This will enter an infinite loop once the end of the file is reached, because since EOF is not zero, its boolean value is true.
The correct way to check the result of fscanf is to compare it with the number of fields expected. Since you are reading one value, you should the return like like this:
while(fscanf(file, "%d", &num) == 1) // <-- return value should be 1 on success

Printing a question mark after a loop [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
Trying to figure out how to print the question mark as so: user inputs: "apple" and then the string gets stored in an array and gets printed like this : "apple?" here is my code:
#include<stdio.h>
int main()
{
char a[23];
int i=0;
printf("enter a single english word: ");
while( (a[i++]=getchar()) != '\n' && i < 23){
a[i] = '\0';
i = 0;
}
while(a[i] != '\0'){
printf("%c",a[i++]);
}
printf("?");
return 0;
}
You are resetting i after each character read. That is effectively making you erase whatever was stored. you need to move i = 0; from inside the first while loop to just after it.
The code you have inside the first while loop should be done after the loop is done. You do all the work of the loop in the while() header. The loop body was resetting i back to 0 each time, so you were repeatedly overwriting the first character of a.
while( (a[i++]=getchar()) != '\n' && i < 23){
}
a[i] = '\0';
i = 0;
First of all, your input loop is incorrect. It should be like so:
while( (a[i++]=getchar()) != '\n' && i < 23) {}
a[i] = '\0';
As the comments to your question say above, you are resetting the pointer index after each character is read, therefore reading character 0 of the array every time. You should do this after the loop.
Also, because a is just a string, you should be able to just print it like this (without the loop):
printf("%s?", a);
Final Program:
#include<stdio.h>
int main()
{
char a[23];
int i=0;
printf("enter a single english word: ");
while( (a[i++]=getchar()) != '\n' && i < 23) {}
a[i] = '\0';
printf("%s?",a);
return 0;
}
The follwoing logic works:
char a[23];
int i=0,j=0;
printf("enter a single english word: ");
To scan the input into an array :
for(a[i]=getchar(); (a[i]!='\n') && (i<23) ; i++)
;
And finally printing :
for(j=0;j<i;j++)
putchar(a[j]);
Hence the program :
#include<stdio.h>
int main()
{
char a[23];
int i=0,j=0;
printf("enter a single english word: ");
for(a[i]=getchar(); (a[i]!='\n') && (i<23) ; i++)
;
for(j=0;j<i;j++)
putchar(a[j]);
printf("?");
return 0;
}

Resources