Strange behavior with fgetc() removing from a FILE stream - c

I have a very large program right now that I'm fairly certain that I should not publish publicly without getting into a lot of trouble so I'm going to try my best to explain the issue at hand.
I have 3 different functions, the names are different but the pointer names in the function match exactly, I'm not allowed to change the pointer names:
int function_1 (FILE \*in, FILE \* out, FILE \*changes);
int function_2(TYPEDEF STRUCT \*s, FILE \*in);
int function_3(TYPEDEF STRUCT \*s, FILE \*in);
My main function calls function_1 using function_1(stdin, stdout, changes) where changes is a pointer to a file stream that was opened in main.
In function1, I call function2(s,changes) and function_3(s,changes) in a loop. I also use fgetc(in) in function_1 after calling 2 and 3. I am failing in the first loop because I have a mismatch comparing characters between changes and stdin, when the are supposed to be the same.
For some strange reason, I find that by the time I get to the line int a=fgetc(in) in function_1, the stdin FILE stream has already lost two characters. If I add a line to fgetc(in) prior to calling function_2*,* I get the first letter in stdin and then my original int a=fgetc(in) shifts down one letter. Using this method, I determined that a character from stdin is lost after a call to function2 and another character from stdin is lost after function_3. However, I did not pass the *in pointer into those functions, I passed the *changes pointer.
I have never been more confused as to why this is happening, it doesn't make sense. If there was a problem with the fgetc(in) calls in the other two functions, it shouldn't only take off two characters as there are many of them in the other two functions, and those fgetc(in) calls are pulling the characters from the changes stream correctly.
Has anyone run into this before? Thanks in advance for any guidance.
edit:
I think this is as minimal of an example that I can get. I also just discovered that if I comment out the EOF If statement checks, I no longer lose the two characters.
#include <stdlib.h>
#include <stdio.h>
int next_struct(MYSTRUCT *s, FILE *in) {
int current_c = fgetc(in);
int eof_check= current_c;
if ((eof_check = getchar()) != EOF) {
//do stuff here
}
else {
return EOF;
}
//do more stuff
return 0;
}
int get_struct_c(MYSTRUCT *s, FILE *in) {
int c = fgetc(in);
int eof_check2= c;
if ((eof_check2=getchar()) != EOF) {
//do stuff
}
else {
return EOF;
}
return character;
}
int patch(FILE *in, FILE *out, FILE *diff) {
//intialize typedef struct
//create pointer to struct
while (!feof(diff)) {
if (next_struct(s,diff) == 0) {
//get charaters from diff and add to output
hunk_c = get_struct_c(s,diff);
read_c = fgetc(in);
fprintf(stderr, "%c\n", read_c);
}
return 0;
}

Related

C programming: Returning string from a function

I am tring to print compose a function can get the specific line from a file, like string=extract_line(2), then the string will be the content of the 2nd line of a file.
but when I tried to put the function in a head file, I got Segmentation fault.
Here is my code:
test.c:
#include "extract_line.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
extract_line(2);
extract_line(3);
printf("%s\n", str);
return 0;
}
extract_line.h
#include <stdio.h>
#include <stdlib.h>
#define TEMP_PATH "/home/pi/project/PCD_8544_screen/show_on_LCD/network_speed.txt"
static char str[256];
void extract_line( int Tgt_Line )
{
FILE *fp;
fp=fopen(TEMP_PATH, "r");
// char str[256];
char holder;
int line=0;
while((holder=fgetc(fp)) != EOF) {
if(holder == '\n') line++;
if(line == Tgt_Line) break; /* 1 because count start from 0,you know */
}
if(holder == EOF) {
printf("%s doesn't have the 2nd line\n", fp);
//error:there's no a 2nd
}
int i=0;
while((holder=fgetc(fp)) != EOF && (holder != '\n' )) {
// putchar(holder);
str[i] = holder;
i++;
}
// printf("%s\n",str);
fclose(fp);
// return str;
}
In the following line of code:
printf("%s doesn't have the 2nd line\n", fp);
You're printing a FILE * as though it's expected to point at a string (filename?). As printf expects a char *, this is likely to cause irrational behaviour. Note that your compiler is probably SCREAMING at you about this! Perhaps you meant:
printf("%s doesn't have the 2nd line\n", TEMP_PATH);
Additionally, there's a possibility for a null pointer dereference which would also cause irrational behaviour between the following two lines:
fp=fopen(TEMP_PATH, "r");
// snip! you need to check fp here!
while((holder=fgetc(fp)) != EOF) {
On that note, your loop is infinite on systems where char is an unsigned type, as EOF is negative which can't possibly compare equal to any unsigned values. As fgetc returns an int with an unsigned char within it and holder is a char, the downward conversion discards the information required for your loop to terminate. holder should be defined as an int, instead.
As there's no upper bound on how many characters are read set by your loop, it's possible that str may be accessed (and assigned) out of bounds in str[i] = holder;. This could cause irrational behaviour.
Additionally, it appears there's no explicit assignment of a '\0' string terminator. As str is defined with static storage duration (not to be confused with your static keyword, which provides internal linkage), that won't really cause irrational behaviour, in fact it's quite predictable, but your output might not be as you expect if the first call reads a line longer than the second call.
Finally, just a few nitpick notes:
I suggest using size_t rather than int for variables which are expected to count or refer to array elements (e.g. int i=0; should be size_t i=0;). This is to make it explicit that negative numbers aren't acceptable, which might also speed your code up a little.
It's a little bit strange to put code in header files. Usually definitions only go into header files, which we #include, and code goes into code files, which we link to (e.g. gcc -o x.c compiles x.c, then gcc main.c x.o compiles main.c and links it with x.o).
You need to have a main() function or you need to run the script from within any other function..
#include "extract_line.h"
#include <stdio.h>
#include <stdlib.h>
void main() {
extract_line(2);
extract_line(3);
printf("%s\n", str);
}

Reading in char from file into struct

For my assignment, I have to read in a text file with a varying amount of lines. They follow the following format:
AACTGGTGCAGATACTGTTGA
3
AACTGGTGCAGATACTGCAGA
CAGTTTAGAG
CATCATCATCATCATCATCAT
The first line is the original line I will testing the following ones against, with the second line giving the number of remaining lines.
I'm having trouble trying to save these to a struct, and can't even get the first line to save. I tried using the void function with an array and it seems to work, but can't seem to transfer it over to structs.
Here's my code so far:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
int main(){
char filename[] = "input1.txt";
FILE *input = fopen("input1.txt","r");
char firstDna[LENGTH]="";
struct dna first;
struct dna first.code[]= "";
makeArray(input,first);
// printf("%s",filename);
system("pause");
return 0;
}
void makeArray(FILE *input,struct dna first){
int i=-1;
//nested for loops to initialze array
//from file
while(i != '\n'){
fscanf(input,"%c",first[i].code);
printf("%c", first[i].code);
i++;
}//closing file
fclose(input);
}
Since this is for a class assignment, I want to preface this by saying that a good way to tackle these types of assignments is to break it up into tasks, then implement them one by one and finally connect them. In this case the tasks might be something like:
parse the first line into a (struct containing a) char array.
parse the number into an int variable
parse each remaining line in the file like you did with the first line
test the first line against the other lines in the file (except the number)
You also mentioned in a comment that the struct is for extra credit. For that reason, I'd recommend implementing it using just a char array first, then refactoring it into a struct once you have the basic version working. That way you have something to fall back on just in case. This way of developing might seem unnecessary at this point, but for larger more complicated projects it becomes a lot more important, so it's a really good habit to get into as early as possible.
Now, let's look at the code. I'm not going to give you the program here, but I'm going to identify the issues I see in it.
Let's start with the main method:
char filename[] = "input1.txt";
FILE *input = fopen("input1.txt","r");
This opens the file you're reading from. You're opening it correctly, but the first line is in this case unnecessary, since you never actually use the filename variable anywhere.
You also correctly close the file at the end of the makeArray function with the line:
fclose(input);
Which works. It would, however, probably be better style if you put this in the main method after calling the makeArray function. It's always a good idea to open and close files in the same function if possible, since this means you will always know you didn't forget to close the file without having to look through your entire program. Again, not really an issue in a small project, but a good habit to get into. Another solution would be to put the fopen and fclose functions in the makeArray function, so main doesn't have to know about them, then just send the char array containing the filepath to makeArray instead of the FILE*.
The next issue I see is with how you are passing the parameters to the makeArray function. To start off, instead of having a separate function, try putting everything in the main method. Using functions is good practice, but do this just to get something working.
Once that's done, something you need to be aware of is that if you're passing or returning arrays or pointers to/from functions, you will need to look up the malloc and free functions, which you may not have covered yet. This can be one of the more complex parts of C, so you might want to save this for last.
Some other things. I won't go into detail about these but try to get the concepts and not just copy paste:
struct dna first.code[]= ""; should probably be first.code[0] = \0;. \0 is used in C to terminate strings, so this will make the string empty.
Passing %c to fscanf reads a single character (you can also use fgetc for this). In this case, it will probably be easier using %s, which will return a word as a string.
Assuming you do use %s, which you probably should, you will need to call it twice before the loop - once to get the first DNA sequence and another time to get the number of other DNA sequences (the number of iterations).
Each iteration of the loop will then test the original DNA sequence against the next DNA sequence in the file.
I hope that helps!
sample to fix
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
struct dna *makeArray(FILE *input, int *n);//n : output, number of elements
int main(void){
char filename[] = "input1.txt";
FILE *input = fopen(filename,"r");
struct dna first = { "" };
fscanf(input, "%24s", first.code);//read first line
printf("1st : %s\n", first.code);
int i, size;
struct dna *data = makeArray(input, &size);//this does close file
for(i = 0; i < size; ++i){
printf("%3d : %s\n", i+1, data[i].code);
}
free(data);//release data
system("pause");
return 0;
}
struct dna *makeArray(FILE *input, int *n){//n : output, number of elements
int i;
fscanf(input, "%d", n);//read "number of remaining lines"
struct dna *arr = calloc(*n, sizeof(struct dna));//like as struct dna arr[n] = {{0}};
for(i = 0; i < *n; ++i){
fscanf(input, "%24s", arr[i].code);
}
fclose(input);
return arr;
}
a simple fix might be :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
void makeArray(FILE *input,struct dna *first){
int i=0;
fscanf(input,"%c",&first->code[i]);
printf("%c",first->code[i]);
while(first->code[i] != '\n' && i < LENGTH){
i++;
fscanf(input,"%c",&first->code[i]);
printf("%c",first->code[i]);
}
}
int main() {
struct dna first;
char filename[] = "input1.txt";
FILE *input = fopen(filename,"r");
makeArray(input,&first);
fclose(input);
printf("%s",first.code);
return 0;
}
PS: i tried to not change your original code
in order to change the code[Length] in the makeArray function you will have to pass it's adresse this is why i call mkaeArray function this way : makeArray(input,&first);.

How to make backslash character not to escape

I don't know the title correctly addresses my problem or not. So, I will just go with it.
Here is the problem, I have to input a char array of a file path (in Windows) containing lots of backslashes in it, eg. "C:\myfile.txt" and return an unsigned char array of C-style file paths, eg. "C:\myfile.txt".
I tried to write a function.
unsigned char* parse_file_path(char *path);
{
unsigned char p[60];
int i,j;
int len = strlen(path);
for(i=0,j=0; i<len; i++, j++)
{
char ch = path[i];
if(ch==27)
{
p[j++]='\\';
p[j]='\\';
}
else
p[j] = path[i];
}
p[j]='\0';
return p;
}
The weird thing (for me) I am encountering is, here path contains only one backslash '\'. In order to get one backslash, I have to put '\' in path. This is not possible, cause path cannot contain '\'. When I call it like this parse_file_path("t\es\t \it), it returns
t←s it. But parse_file_path("t\\es\\t \\it") returns t\es\t \it.
How can I accomplish my task? Thanks in advance.
If I can just mention another problem with your code.
You are returning a local variable (your unsigned char p). This is undefined behavior. Consider declaring a char* p that you assign memory to dynamically using malloc and then returning p as you do. E.g. something like:
char* p = malloc(60);
A common practice is to use sizeof when allocating memory with malloc but here I've passed 60 directly as the C standard guarantees that a char will be 1 byte on all platforms.
But you have to free the memory assigned with malloc.
Or alternatively, you can change the function to take a buffer as an input argument that it then writes to. That way you can pass a normal array where you would call this function.
Regarding your slashes issue, here:
p[j++]='\\';
p[j]='\\';
Position j in p will be changed to \\, then j will be incremented and at the very next line you do the same for the succeeding char position. Are you sure you want the two assignments?
By the way if you are inputting the path from the command line, the escaping will be taken care of for you. E.g. consider the following code:
#include <stdio.h>
#include <string.h> /* for strlen */
#include <stdlib.h> /* for exit */
int main()
{
char path[60];
fgets(path, 60, stdin); /* get a maximum of 60 characters from the standard input and store them in path */
path[strlen(path) - 1] = '\0'; /* replace newline character with null terminator */
FILE* handle = fopen(path, "r");
if (!handle)
{
printf("There was a problem opening the file\n");
exit(1); /* file doesn't exist, let's quite with a status code of 1 */
}
printf("Should be good!\n");
/* work with the file */
fclose(handle);
return 0; /* all cool */
}
And then you run it and input something like:
C:\cygwin\home\myaccount\main.c
It should print 'Should be good!' (provided the file does exist, you can also test with 'C:\').
At least on Windows 7 with cygwin this is what I get. No need for any escapes as this is handled for you.

How can I count the occurrences of a character in a file?

The function is called as so,
printf("%d occurrences of %c in %s\n",
countoccurrences(argv[1], argv[1][0]),
argv[1][0], argv[1]);
and this is my function so far:
/* countcharinfile
* input: char *filename, char c
* output: the number of occurrences of char c inside file filename
*/
int countoccurrences(char *filename, char c)
{
// count the number of occurrences of c in the file named filename
FILE *fp = fopen(filename,"r");
int ch,count=0;
while ((ch = fgetc(fp) != EOF))
{
if (ch == c)
count++;
}
return count;
}
When I run the program, ./main Today is a beutiful day
I get the error Segmentation fault (core dumped)
It looks like you're using your function countoccurrences in main before it's been defined.
Add a function signature before main:
int countoccurrences(char *, char);
Or move the function itself to a place in your code before your main function.
Also:
you need to initialize your count variable to zero in countoccurences, and
you should check that fp != NULL before you use the file pointer. fopen will return NULL if it can't open the file.
When I run the program, ./main Today is a beutiful day
When you run your program this way, you are passing it 5 arguments, one for each word in your sentence. Review your function and your function call in main: the function wants a file name to search, which should be the first argument to your program, not the text to search. And the second argument should be the character to search for.
Since you're not checking the return value of fopen, your invocation here will cause problems, because you probably don't have a file named Today in the working directory.
C needs to know about your function signature before the call. Either:
Move your function before the call, or
Put a declaration before the call (at the global scope of course)
int countoccurrences(char *filename, char c);
You also need to initialize count (presumably to 0). You should make sure you are calling it with the right value. If you want to use the first character of the second parameter you should use argv[2][0].
The error indicates that the function declaration or definition was not visible at the point where it is called. Move the definition or put a declaration prior to main().
Other points:
Check return value of fopen()
Initialise count
buf is an unused local variable
For example:
FILE *fp = fopen(filename,"r");
if (fp)
{
int ch,count=0;
while ((ch = fgetc(fp)) != EOF)
{
if (ch == c) count++;
}
fclose(fp);
}
else
{
fprintf(stderr,
"Failed to open %s: %s\n",
filename,
strerror(errno));
}

How to implement puts() function?

I have tried to implement the puts function.It in actual returns a value but i cant get what should it return.please check my code and guide me further
/* implementation of puts function */
#include<stdio.h>
#include<conio.h>
void puts(string)
{
int i;
for(i=0; ;i++)
{
if(string[i]=='\0')
{
printf("\n");
break;
}
printf("%c",string[i]);
}
}
See comments in code.
int puts(const char *string)
{
int i = 0;
while(string[i]) //standard c idiom for looping through a null-terminated string
{
if( putchar(string[i]) == EOF) //if we got the EOF value from writing the char
{
return EOF;
}
i++;
}
if(putchar('\n') == EOF) //this will occur right after we quit due to the null terminated character.
{
return EOF;
}
return 1; //to meet spec.
}
And, as an aside - I've written the equivalent of putc, puts several different times in relation to developing on embedded systems. So it's not always just a learning exercise. :)
Comment on EOF: It is a POSIX constant from stdio.h.
In my Linux stdio.h, I have this definition:
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
That definition code is GPL 2.1.
From the manual page:
#include <stdio.h>
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);
int puts(const char *s);
Return Value
fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.
puts() and fputs() return a non-negative number on success, or EOF on error.
Well, stdio's puts() returns a non-negative number on success, or EOF on error.
What's string supposed to be? You should define your function better, try:
void my_puts(const char *string)
instead of
void puts(string)
As noted in the link I included, you need to specify the data type of the argument you're passing (in your example string) and you cannot use the name of a function which has already been defined (i.e. puts ).
In addition to what has already been said, I am personally opposed to redefining standard library functions. However, if you absolutely must (e.g. for a homework assignment), and your compiler is complaining about conflicting types for 'puts', try putting this at the top:
#define puts _puts
#include <conio.h>
#include <stdio.h>
#undef puts
I don't see any point in implementing puts!
anyway, you should read the specs of puts so you can make it.
this may help
int myputs(char* s)
{
int x = printf("%s\n", s);
return (x > 0) ? x : EOF;
}
you should include stdio.h so you can use printf and EOF.
Note that this is not EXACT implementation of puts, because on error puts sets an error indicator and do some other stuff.
More details about puts, here.

Resources