passing string to scanf - c

I am trying to make a program that generates a string given user input, and then passes that string to a function that will change stdin to a dummy file, write the string to the file, use scanf on said file, then delete the file, but I'm having trouble redirecting stdin to the dummy file, any help on the best action that will only extend into the scope of the function?
int scan(const char* __restrict__ _format, ...){
FILE* original = stdin, *mod = calloc(1, sizeof(FILE));
mod = freopen("testFile.txt", "w+", stdin);
fputs(_format, stdin);
int a, b;
scanf("%d %d", &a, &b);
printf("%d, %d", a, b);
// freopen(orig)
return 1;
}
void swap(char* a, char* b) {
if (*a != ' ' && *b != ' ') {
char temp = *a;
*a = *b;
*b = temp;
}
}
void permiate(char* str, int start, int end){
int i;
if(start == end){
printf("%s\n", str);
}else{
for(i = start; i<=end; i++){
swap(str+start, str + i);
permiate(str, start + 1, end);
swap(str + start, str + i);
}
}
}
int main(){
int a, b;
char str[] = "1 3";
//function to put string to stdio
scan(str);
scanf("%d %d", &a, &b);
printf("%d, %d", a, b);
return 0;
}
after someone pointed out fscanf, a function i was never aware of becasue my teacher never covered it, i have found a working solution to the scan function:
int scan(const char* __restrict__ _format, ...){
int *a = malloc(sizeof(int)), i = 0;
FILE *fp1 = fopen("testfile.txt", "w");
fputs(_format, fp1);
freopen("testFile.txt", "r", fp1);
while(fscanf(fp1, "%d", &a[i]) != EOF){
i++;
a = realloc(a, sizeof(int)*i);
}
for(int j = 0; j < i; j++){
printf("%d, ", a[j]);
}
fclose(fp1);
return 1;
}
but whenever i give str a value like "1 2 3 4 5 6 ..." or anything that has more than 5 numbers, the 5th number is always 0 if i leave realloc in, if i comment that line out, then it is fine. any idea on what that is about? ps my labs at uni only got to basic uses of arrays, no dynamic memory or anything, so if im using anything wrong it would b greatly appriciated

Alright, I think I understand what you are attempting to do, and it is doable, but I certainly would not recommend it. Whenever you freopen() one of the standard streams, there is no portable way to restore the original standard stream. You can remove original from your function as it will not work. Also do not allocate for mod.
With that said, you can write your scan function as:
int scan(const char* __restrict__ format)
{
int a, b;
FILE *mod = freopen ("dat/freopenab.txt", "w", stdin);
if (!mod) {
perror ("freopen-mod-write");
return 0;
}
fputs (format, stdin); /* write to file as stdin */
stdin = freopen (NULL, "r", mod); /* reopen file "r" as stdin */
if (!stdin) {
perror ("freopen-stdin-read");
return 0;
}
if (scanf("%d %d", &a, &b) != 2) { /* read values from file */
fputs ("error: read of int values failed.\n", stderr);
return 0;
}
printf("%d, %d\n", a, b); /* output resutls */
return 1;
}
stdin is reopened as file "dat/freopenab.txt" above. The format string is written to the file via the reopened stdin. Then freopen() is called again with NULL as the pathname which allows you to change the mode of the existing stream mod to read and assign the return to stdin (making stdin read from the file)
(note: variable names with leading underscores are best avoided)
A full example would be:
#include <stdio.h>
int scan(const char* __restrict__ format)
{
int a, b;
FILE *mod = freopen ("dat/freopenab.txt", "w", stdin);
if (!mod) {
perror ("freopen-mod-write");
return 0;
}
fputs (format, stdin); /* write to file as stdin */
stdin = freopen (NULL, "r", mod); /* reopen file "r" as stdin */
if (!stdin) {
perror ("freopen-stdin-read");
return 0;
}
if (scanf("%d %d", &a, &b) != 2) { /* read values from file */
fputs ("error: read of int values failed.\n", stderr);
return 0;
}
printf("%d, %d\n", a, b); /* output resutls */
return 1;
}
int main (void) {
scan ("12 34\n");
}
Example Use/Output
$ ./bin/freopenab
12, 34
Resulting Output/Input File
$ cat dat/freopenab.txt
12 34
Again, there is no portable way to restore stdin to it original state, though on Linux you can look at using "/dev/tty" or "/dev/stdin". Look things over, and give it a try. Then avoid freopen() unless there is no other way to do what you need to do in favor of just using fopen, fclose, and fopen again.

Related

Wrong output for reading data from file into program

I've been working on a program to read data from file into a program and print it:
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p;
int e;
float f;
static char a[50];
FILE *fp;
fp = fopen("new_input.txt", "r");
if (fp == NULL)
exit(0);
while (1)
{
p = fgets(a, 50, fp);
if (p == NULL)
break;
printf("%s", a);
printf("\n");
fscanf(fp, "%d", &e);
printf("%d", e);
printf("\n");
fscanf(fp, "%f", &f);
printf("%f", f);
printf("\n");
}
fclose(fp);
return 0;
}
Contents of file new_input.txt are:
Girik
12
19.98
Nikhil
13
90.89
On running on OnlineGdb however I get the following output:
Girik
12
19.980000
12
19.980000
khil
13
90.889999
Can someone explain the problem with my code?
I'm concerned about incomplete name "Nikhil" in output and printing of the value 12 and 19.99 twice.
Link to code:
https://onlinegdb.com/r1ufoP8-d
The problem arises because the last fscanf does not parse the \n, so when the cycle restarts the fgets will parse it and print it, naturally the next fscanf is not able to parse the string ("Nikhil", which was not parsed), because it expects an int, it's downhill from there, as the values are not parsed, what's printed is the old values of e and f from the previous cycle.
If you change your last fscanf so it parses the \n everything works fine:
Live demo
while (1)
{
p = fgets(a, 50, fp);
if (p == NULL)
break;
printf("%s", a);
fscanf(fp, "%d", &e);
printf("%d", e);
printf("\n");
fscanf(fp, "%f\n", &f); //<--here
printf("%.2f", f);//.2f specifier so it prints only 2 decimal places
printf("\n");
}
The pointer is also unnecessary you can use fgets itself as a condition i.e.:
while (fgets(a, sizeof a, fp)) //will read until the end of the file
{
printf("%s", a);
//... same code
}
Anyway, here is a version you can use that will render you the expected result and output, and, I would argue, is better:
Live demo
#include <stdio.h>
#include <stdlib.h>
int main()
{
int e;
float f;
static char a[50];
FILE *fp;
fp = fopen("new_input.txt", "r");
if (fp == NULL){
return EXIT_FAILURE;
}
// will parse until \n or 49 characters max (given the container size)
while (fscanf(fp, " %49[^\n]", a) > 0)
// ^ space - will discard any blank characters
{
printf("%s\n", a);
if(fscanf(fp, "%d", &e) > 0){
printf("%d\n", e);
}
if(fscanf(fp, "%f", &f) > 0){
printf("%.2f\n", f);
}
}
fclose(fp);
return EXIT_SUCCESS;
}
I also added the checks for the fscanf returns which is always a good practise.
Or even:
//...
while (fscanf(fp, " %49[^\n]%d%f", a, &e, &f) == 3)
{
printf("%s\n%d\n%.2f\n", a, e, f);
}
//...
However, the best solution, I believe, is to parse everything with fgets and convert the values with sscanf or strtol/strtof, it's a more robust option. Give it a try.
For "read data from file into a program and print it", you can use e.g. fgets or fscanf. Both uses are included in the following adaption of your example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p;
int e;
float f;
static char a[50];
FILE *fp;
// use fgets
printf("\nVersion with using fgets\n\n");
fp = fopen("new_input.txt", "r");
if (fp == NULL) exit(0);
while(fgets(a, 50, fp)!=NULL)
{
printf("%s", a);
}
fclose(fp);
// use fscanf
printf("\nVersion with using fscanf\n\n");
fp = fopen("new_input.txt", "r");
if (fp == NULL) exit(0);
while(fscanf(fp,"%s\n",a)!=EOF)
{
printf("%s\n", a);
}
fclose(fp);
return 0;
}
COMMENTS:
Size of a[50] needs to be larger than maximum line size.
You can also fscanf for numbers (if you are sure, that it is a number).
Check, if string is integer or float (locale) is a new topic.
Another option: With the assumption that you can rely on the format in "new_input.txt" (to account for the comment of Devolus).
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p;
int g;
float f;
static char a[50];
FILE *fp;
fp = fopen("new_input.txt", "r");
if (fp == NULL) exit(0);
while(fscanf(fp,"%s\n",a)!=EOF){
printf("%s\n", a);
fscanf(fp,"%d\n",&g);
printf("%d\n", g);
fscanf(fp,"%f\n",&f);
printf("%f\n", f);
}
fclose(fp);
return 0;
}

Struct fscanf in file C

In file I need to read some inputs:
this is an example:
8 15
[1,1] v=5 s=4#o
[4,2] v=1 s=9#x
typedef struct{
int red2;
int stupac2;
int visina;
int sirina;
char boja[10];
}Tunel;
FILE* fin = fopen("farbanje.txt", "r");
Tunel* tuneli = malloc(sizeof(Tunel)*50);
// if(fin!=0)
fscanf(fin,"%d %d", &r,&s);
printf("%d %d", r,s);
int p=0;
while (fscanf(fin, "[%d,%d]", &tuneli[p].red2, &tuneli[p].stupac2) == 2)
{
p++;
}
for(i=0;i<p;i++)
{
printf("[%d,%d]", tuneli[i].red2, tuneli[i].stupac2);
}
Problem is that it wont read me properly inputs from here: [1,1] v=5 s=4#o
Last line where i use printf shows some random numbers.
Agree it is better to use fgets
But if you want to continue to use your current approach,
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int red2;
int stupac2;
int visina;
int sirina;
char boja[10];
}Tunel;
int main(){
int r, s, i;
FILE*fin=fopen("farbanje.txt", "r");
if(fin==NULL) {
printf("error reading file\n");
return 1;
}
Tunel *tuneli=(Tunel*)malloc(sizeof(Tunel)*50);
fscanf(fin,"%d %d\n", &r,&s);
printf("%d %d", r,s);
int p=0;
while (fscanf(fin, " [%d,%d]%*[^\n]", &tuneli[p].red2, &tuneli[p].stupac2) == 2)
{
p++;
}
fclose(fin);
for(i=0;i<p;i++)
{
printf("[%d,%d]", tuneli[i].red2, tuneli[i].stupac2);
}
}
Last line where i use printf shows some random numbers....
The random numbers you see are because the buffers to print were not properly populated yet.
This example shows how to read the file, using fgets() to read a line buffer, then use sscanf() to parse the first two values from the lines. (read in-code comments for a few other tips.)
int main(void)//minimum signature for main includes 'void'
{
int r = 0;
int s = 0;
char line[80] = {0};//{initializer for arrays}
int p = 0;
Tunel *tuneli = malloc(sizeof(*tuneli)*50);
if(tuneli)//always test return of malloc before using it
{
FILE *fin = fopen(".\\farbanje.txt", "r");
if(fin)//always test return of fopen before using it
{
fgets(line, sizeof(line), fin);
sscanf(line, "%d %d", &r, &s);
while(fgets(line, sizeof(line), fin))
{
sscanf(line, " [%d,%d]", &tuneli[p].red2, &tuneli[p].stupac2);
//note space ^ here to read only visible characters
printf("[%d,%d]\n", tuneli[p].red2, tuneli[p].stupac2);//content is now populated corretly
p++;
}
fclose(fin);//close when finished
}
free(tuneli);//free when done to prevent memory leaks
}
return 0;
}

fscanf always returns 0(CLOSED)

I am a beginner in C programming, and I am trying to write a simple code to read a text file and write its content into an array, then print it on console. However, I always get 0.0000, and I could not solve the problem.
#include <stdio.h>
#include <stdlib.h>
int numOfLines(FILE *fp1);
void printarr(float arr[], int size);
float *filetoArr(FILE *fp, int arrsize);
int main(int argc, const char *argv[]) {
char *fileName1 = argv[1];
FILE *fp1 = fopen(fileName1, "r");
printf("File name: %s", fileName1);
int size = numOfLines(fp1);
printf("Number of lines in the file: %d\n", size);
float *arr = filetoArr(fp1, size);
printarr(arr, size);
free(arr);
fclose(fp1);
}
void printarr(float *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%f ", *(arr + i));
}
}
float *filetoArr(FILE *fp, int arrsize) {
int size = arrsize;
float *arr = (float *)malloc(sizeof(float) * size);
for (int i = 0; i < size; i++) {
fscanf(fp, "%f\n", (arr+i));
}
return (arr);
}
int numOfLines(FILE *fp1) {
int numberOfLines = 0;
char c;
do {
c = getc(fp1);
if (c == '\n') {
numberOfLines++;
}
} while (c != EOF);
return numberOfLines;
}
your numOfLines goes to the end of the file.
You have to rewind(fp1) to reset your file handle to position 0, or fscanf hits the end of the file, and doesn't read anything (check return code from fscanf: it should be 1 I bet you're getting 0 all the time)
There are multiple problems in your code:
you read the whole file in numOfLines(): you must reset the file pointer to the beginning of file with rewind(fp1); so fscanf() can read the file instead of hitting the end of file immediately.
the variable c used to read bytes from the file must be defined as an int for the test for end of file to be reliable. Otherwise, depending on whether char is signed or not by default, the EOF would never match or could potentially match the character \377 as end of file erroneously.
you do not check for failure to open the file.
Although returning 0 is implicit for function main() since C99, it is advisable to write the return 0; statement explicitly for better clarity.

Why is my_getline() causing a system hang?

This program attempts to save the contents of a text file into a character variable array. It is then supposed to use my_getline() to print the contents of the character array. I've tested and see that the contents are in fact getting saved into char *text but I can't figure out how to print the contents of char *text using my_getline(). my_getline is a function we wrote in class that I need to use in this program. When I attempt to call it in the way that was taught, it 1 is printed to terminal but then the terminal just waits and nothing else is printed. Any guidance would be appreciated. Also, let me know if I'm missing any information that would help.
/* Include the standard input/output and string libraries */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* Define the maximum lines allowed in an input text and NEWLINE for getline funct. */
#define MAXPATTERN 15
#define MAXFILENAMELENGTH 15
#define NEWLINE '\n'
/* function prototypes */
void my_getline(char text[]);
int find_string(char text[], char pattern[], int length_text, int length_pattern);
int main()
{
FILE *fp;
long lSize;
char *text;
char fileName[MAXFILENAMELENGTH], pattern[MAXPATTERN];
char c;
int length_text, length_pattern, j, lineNumber = 1;
printf("Enter file name: ");
scanf("%s", fileName);
fp = fopen(fileName, "r");
if (fp == NULL)
{
printf("fopen failed.\n");
return(-1);
}
fseek(fp, 0L, SEEK_END);
lSize = ftell(fp);
rewind(fp);
/* allocate memory for all of text file */
text = calloc(1, lSize + 2);
if(!text)
{
fclose(fp);
fputs("memory allocs fails", stderr);
exit(1);
}
/* copy the file into text */
if(1 != fread(text, lSize, 1, fp))
{
fclose(fp);
free(text);
fputs("Entire read fails", stderr);
exit(1);
}
text[lSize + 1] = '\0';
printf("%s has been copied.\n", fileName);
rewind(fp);
printf("%d ", lineNumber);
for (j = 0; (j = getchar()) != '\0'; j++)
{
my_getline(text);
printf("%d %s\n", j+1, text);
}
printf("Enter the pattern you would like to search for: ");
scanf("%s", pattern);
printf("\nYou have chosen to search for: %s\n", pattern);
fclose(fp);
free(text);
return(0);
}
void my_getline(char text[])
{
int i = 0;
while ((text[i] = getchar()) != NEWLINE)
++i;
text[i] = '\0';
}
Your function is causing a system hang because you're calling getchar(), which returns the next character from the standard input. Is this really what you want?
At this point, your program is expecting input from the user. Try typing in the console windows and pressing to see it coming back from the "hang"
It is most likely causing an infinite loop because you are not checking whether you have reached EOF.
void my_getline(char text[])
{
int i = 0;
int c;
while ( (c = getchar()) != NEWLINE && c != EOF )
text[i++] = c;
text[i] = '\0';
}

c, 2d char array and fopen

I'm trying to make a program that reads a file with list of names. The number of those names can vary, as well as the names lengths. I want to store them in an array of arrays of char, and read each row as a string to later open the file that corresponds to the name in question. But when I try to open the first one, I have an error opening file.
I'm totally out of ideas.
Help, please?
Here is the code relevant to this action:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int glimps(char *fname);
int write_av(char *fname, int NumbFiles);
int clr(char *fname);
int readFile(char *fname, int i);
double *dalpha, *alpha, *Ln_t, *LnLnA, Conc;
long *time, *weights, *Lmax, Nmax;
char *av_file, **in_files, *antetka;
/****************************************************************************/
int main(int argc, char *farg[])
{
int i, NumbFiles, flag;
long row;
char *a1;
FILE *fp;
av_file = farg[1];
printf("av_file = %s\n",av_file);
NumbFiles = glimps(av_file);
in_files = (char **) malloc (sizeof(char *) * NumbFiles);
for (i=0 ; i<NumbFiles ; i++)
in_files[i] = (char *) malloc (sizeof(char) * 200);
Lmax = (long *) calloc((size_t) NumbFiles, sizeof(long));
if((in_files == NULL)||(Lmax==NULL)) printf("Грешка при read алок.\n, "), exit(-1);
if (flag = readFile(av_file, -1))
printf("Error in read av_file %s\n", av_file), exit(-1);
weights = (long *) calloc((size_t) Nmax, sizeof(long));
for(i = 0; i<Nmax; i++) weights = 0;
for(i = 0; i<NumbFiles; i++)
{
//if (flag = readFile(&(*in_files[i]), i))
if (flag = readFile(in_files[i], i))
printf("Error in in_files[%d], %s\n",i, &(*in_files[i])), exit(-1);
}
if (flag = write_av(av_file, NumbFiles))
printf("Error in write_av(%s)\n,", av_file), exit(-1);
exit(0);
}
/****************************************************************************/
int glimps(char *fname)
{
FILE *fp;
char buf[140];
int cnt=0;
fp = fopen (fname, "r");
while (fgets(buf,140,fp) )
{
cnt++;
}
fclose(fp);
return (cnt);
}
/****************************************************************************/
int readFile(char *fname, int k)
{
int cnt=0;
FILE *fp;
char buf[200], dummy[13];
printf("fname is %s\n", fname); getchar();
fp = fopen (fname, "r");
if(fp==(NULL)) return(-1);
if(!strcmp(fname,av_file) )
{
while (fgets(in_files[cnt++],200,fp) );
}
else
{
printf("read TUK!\n"); getchar();
fgets(buf,200,fp);
sscanf(buf,"%s %s %s %s %s %s %s %ld %s %s %lf\n",
dummy, dummy,dummy,dummy,dummy,dummy,dummy, &Lmax[k],
dummy, dummy, &Conc);
fgets(buf,200,fp);
sscanf(buf,"%s\n", antetka);
printf("read TUK!\n"); getchar();
while (fgets(buf,200,fp))
{
sscanf(buf,"%ld %lf %lf %s %lf %lf\n",
&time[cnt], &dalpha[cnt], &alpha[cnt], dummy, &Ln_t[cnt],
&LnLnA[cnt]);
weights[cnt++]++;
}
}
fclose(fp);
return (0);
}
...
Console Output:
> ./avr alpha_cubeL.C0.010
av_file = alpha_cubeL.C0.010
fname is alpha_cubeL.C0.010
fname is alpha_cubeL100C0.010
Error in read in_files[0], alpha_cubeL100C0.010
> ls alpha_cubeL100C0.010
alpha_cubeL100C0.010
What happens is that in the readFile function, you read the main file given as argument to make (from the content) several file names in in_files[i], but fgets reads lines including the CR or CRLF (ie the end of line character(s)). Thus later in the program, readFile fails as it tries to open filename + CR [LF].
You may just add a trim function near the top of your program, like
void trim(char *s) {
int i,l = strlen(s);
for (i=l-1 ; i>=0 && (s[i]==10 || s[i]==13) ; i--) s[i] = 0;
}
that removes CR and/or LF that end a string s, and then change the readFile function to trim the file names read in each line, like
while (fgets(in_files[cnt++],200,fp) ) {
trim(in_files[cnt-1]); // cnt-1, or do the cnt++ here (and not above...)
}
Then the files can be opened...
(this is probably not the only problem in this program, but this is a good start)

Resources