How do I use pointers in combination with getc? - c

I have a function getNum(), which gets a number from file and returns it. When I go back into getNum() I have lost the pointer and it starts at the begging of the file again. I'm wondering How do I get the location of where getc is and then go back to that place. I couldn't find how to do this in the manual or in forums. Thank you.
#include <stdio.h>
#include <stdlib.h>
int getNum();
int getLine();
int getMatrix();
main() {
int num;
int two;
num = getNum();
printf("%d\n", num);
two = getNum();
printf("%d\n", two);
}
int getNum() {
FILE *infile;
infile = fopen("matrix.txt","r");
int c;
double value = 0;
while ((c=getc(infile)) != '\n') {
if(c==32){
if(value != 0){
return(value);
}
//otherwise keep getting characters
}
else if ((c<=47)||(c>=58)){
printf("incorrect number input %d\n", c);
exit(1);
}
else {
value = (10*value) + c - '0';
}
}
return(value);
}

The reason is that you reopen the file each time you execute getNum. When you open a file for reading, it starts at the start of the file. Instead open it just once.
int main(int argc, char *argv[])
{
...
FILE *infile;
...
infile = fopen("matrix.txt","r");
...
getNum(infile)
...
fclose(infile);
return 0;
}
int getNum(File *infile)
{
// Same as before, just no file opening.
}

You re-open the File each time you Call getNum, so naturally you are back at the start.
Instead open the file in your main and pass the FILE * to getNum().

You're opening the file anew with each function call. The newly opened file begins scanning from the beginning.
An alternative would be to open the file once, outside getNum(). You could pass the FILE* to getNum() as an argument.
Also, you're not closing the file. Use fclose() to close the file after all the calls to getNum().

Something like:
int getNum( FILE* fp );
...
int n;
FILE* file = fopen( "file.txt" );
assert( file );
do {
n = getNum( file );
/* ... */
}
while ( n != -1 ); /* or something */
fclose( file );

Related

Why does (while .. getchar()) does not write to my file, in C?

I need to write a program that asks the user to enter strings, each string ends when the user presses 'Enter'.
The program needs to receive the file name as a parameter, the file should be opened and closed for each operation and for every string entered, the program should append the string to the end of the file (on a new line).
This is my code so far:
int is_file_exists(char *file_name)
{
FILE *file;
if ((file = fopen(file_name,"r"))!=NULL)
{
/* file exists */
fclose(file);
return 1;
}
else
{
//File not found, no memory leak since 'file' == NULL
//fclose(file) would cause an error
return 0;
}
}
int main(int argc, char **argv)
{
char c;
FILE *file;
if (argc >= 2)
{
if (is_file_exists(argv[1]))
{
file = fopen(argv[1], "w");
}
else
{
return 0;
}
}
else
{
file = fopen("file.txt", "w");
}
while ((c = getchar()) != EOF)
{
putc(c, file);
}
return 0;
}
So far the code compiles and file is being created, but nothing is being written inside of it.
Edit: I also need some function pointers, see my comments on selected answer
I think one of the problem was that you were opening and closing a file, and then reopening it subsequently. It is better to just leave it open using a pointer while simultaneously testing that there were no issue to open the file. Another problem was that you were writing in the file, don't you prefer to append text to it? Well it's your decision. As for the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // exit
typedef struct mystruct {
char *exit_word;
void (*exit_fptr)(int); // man exit
int (*strcmp_fptr)(const char *, const char*); // man strcmp
} t_mystruct;
int is_file_exists(char *filename, FILE **file)
{
return (*file = fopen(filename,"a")) > 0;
}
#define BUFF_SIZE 1024
int main(int argc, char **argv)
{
char c;
FILE *file;
t_mystruct s = {.exit_word = "-exit", .exit_fptr = &exit, .strcmp_fptr = &strcmp};
if (argc >= 2) {
if (!(is_file_exists(argv[1], &file)))
return 0;
}
else
file = fopen("file.txt", "a"); // open the file in append mode
char buffer[BUFF_SIZE];
while (42) {
int i = 0;
memset(buffer, 0, BUFF_SIZE);
while ((c = getchar()) != '\n')
buffer[i++] = c;
if (!s.strcmp_fptr(buffer,s.exit_word)) {// exit if user type exit, allow you to fclose the file
fclose(file);
s.exit_fptr(EXIT_SUCCESS); // better to use the define
}
buffer[i] = '\n';
fputs(buffer, file);
}
fclose(file);
return 0;
}
your code can work
remember to press Ctrl+d when finished input. the file will have the content your expected
your code wait for EOF to quit the loop. Ctrl+d is a way to input EOF, or else the program never ends.
putc will write to cache at first, then write to disk. this an optimization mechanism of File System. you can choose to avoid this by DirectIO when open file.
when program terminate normally, file will be closed automatically, then data in cache will be copy to disk;
but when program terminated abnormally, data in cache might be lost.
file should be closed
fclose is needed.
open and close should be organized in pair just as malloc and free.

Text is being appended at beginning of file instead of at end of file

I'm having a weird bug where the text I append is being added to the beginning of a file instead of the end of it. This ends up making everything backwards.
CODE:
#include <stdio.h>
#include <stdlib.h>
//Check Values
void checkValues(int numDisks, int raidType, int chunkSize){
while (numDisks < 1 || numDisks > 9){
printf("Number inputed for numDisks is not valid, please enter a new value (1-9).\n");
scanf("%d", &numDisks);
}
while(raidType < 0 || raidType > 1){
printf("Number inputed for raidType is not valid, please enter a new value (0-1).\n");
scanf("%d", &raidType);
}
while(chunkSize < 1 || chunkSize > 512){
printf("Number inputed for chunkSize is not valid, please enter a new value (1-512).\n");
scanf("%d", &chunkSize);
}
}
//CreateFile
void createFile(int numDisks){
char raidName[5];
int counter = 1;
//Create each file
while(counter != numDisks + 1){
sprintf(raidName, "raid%d", counter); //Append counter to string
FILE *out = fopen(raidName, "w");
counter++;
}
}
//Write File
void writeFile(int numDisks, char *buffer, int counter){
char raidName[5];
sprintf(raidName, "raid%d", counter); //Append counter to string
//Write File
FILE *out = fopen(raidName, "a");
fprintf(out, "%s", buffer);
}
//Read and Write Files
void rwFile(const char *fileName, int chunkSize, int numDisks){
char buffer[10000];
int counter = 1;
//Reading File
FILE *in = fopen(fileName, "r");
if(in == NULL) return;
//Create File
createFile(numDisks);
while(fgets(buffer, chunkSize + 1, in) != NULL){
//Reset Counter
if(counter > numDisks){
counter = 1;
}
writeFile(numDisks, buffer, counter);
counter++;
}
}
int main(int argc, const char *argv[]){
//Declarations
const char *fileName = argv[1];
int numDisks = atoi(argv[2]);
int raidType = atoi(argv[3]);
int chunkSize = atoi(argv[4]);
checkValues(numDisks, raidType, chunkSize);
rwFile(fileName, chunkSize, numDisks);
}
raid1.txt:
mmmmiiiieeeeaaaa
What should be written to raid1.txt:
aaaaeeeeiiiimmmm
I have tried using fseek but to no avail. If anybody could help me out or point me in the right direction that would help. This is done in C using bash to compile and run the program. The arguments that are passed are test.txt 4 0 4.
I imagine the problem you are seeing is due to each call to writeFile is opening a fresh handle to the file, writing to it and then just returning. Once you have finished using a file handle you should close it, this will flush the file buffer to the file and free up the handle.
What I think is happening here is you are opening up a fresh handle each time and each of these is only having a small amount of data written to it, so isn't being flushed to disk. You program is then exiting and the OS is cleaning up the stale file handles flushing them to disk. As a guess I imagine it is doing that clean up in reverse order hence the appearance of your file being written backwards.
Update your writeFile to include a close and hopefully that should resolve the issue
FILE *out = fopen(raidName, "a");
fprintf(out, "%s", buffer);
fclose(out);
It might be nicer if you open the file for writing in the loop calling writeFile and pass the handle over, and then you only need to open it and close it once.
Worth adding closes elsewhere, where you have opened files too.
HTH
One more thing I see you are using address of local variables for scanf in check values(k), these are local only and Never going to be reflected in Main()

Get the user to enter a name but using file stream *fp

I am a beginner in c so I have a problem with get the user to input last name, a comma & then first name. However it will pass to the function call
int get_name(FILE *fp)
in my main function. I have a problem either if I have to use the arguments parameters.
Example, main (int argc, char *argv[])) or just main (void))
and from what I have been searching so far, FILE*fp cannot get the user to enter from stdin it only use to open the file(?) BUT I am required to get the user to input from keyboard and pass to the function. I have written some codes. but they don't seem to work but I am going to put down on here the one I am sure that I need a few changes most.
#define LINESIZE1024
int main(void){
FILE *fp;
char line[LINESIZE];
char first;
char last;
char comma;
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(fp = (sscanf(line,"%s %s %s",&last,&comma,&first)==3))
get_name(fp);
if(get_last_first(fp)== -1)
break;
printf("Please enter first name a comma and then last name");
}
BUT I got an error saying I can't use pass it from pointer to an integer. and many MORE but I accidentally closed my concolse and all the errors that appeared while I was trying to fix are gone. So please give me some ideas.
What about seconde code
while(1){
if(!fgets(line,LINESIZE,fp)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s %s %s",last,comma,first)==3)
get_last_first(fp);
return 0;
}
It gave me errors too. fp,last,first,comma used uninitialized in this function
OK so I think I have fixed the previous problem now. However it doesn't print the name back if the name is given correctly. Here is my fixed main code.
int main(void){
FILE *fp = stdin;
char line[LINESIZE];
char first[16];
char last[16];
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s ,%s",last,first)==2)
if(get_name(fp)==2)
printf("Your name is: %s %s\n", first, last);
}
return 0;
}
here is my function.
int get_name(FILE *fp){
char line[LINESIZE];
char last[16], first[16];
int n;
/* returns -1 if the input is not in the correct format
or the name is not valid */
if(fgets(line, LINESIZE, fp) == NULL) {
return -1;
}
/* returns 0 on EOF */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == EOF) {
return 0;
}
/* prints the name if it's valid */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == 2) {
return 2;
}
return 1;
}
I thank you people so much for taking time to read and help me. Please don't be mean :)
Seems that you are making it more complicated than needed. Don't call fgets and scanf in main. Only do that in the function get_name.
It can be something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINESIZE 1024
int get_name(FILE *fp)
{
char line[LINESIZE];
char* t;
if(!fgets(line, LINESIZE,fp))
{
printf("Error reading input\n");
return 0;
}
t = strstr(line, ",");
if (t)
{
*t = '\0';
++t;
printf("First: %s - Last: %s\n", line, t);
return 2;
}
printf("Illegal input\n");
return 0;
}
int main(int argc, char **argv)
{
get_name(stdin);
return 0;
}
If you later decide that you want to read from a file, you can reuse the function get_name without changing it at all. All you need is to change main. Like:
int main(int argc, char **argv)
{
FILE* f = fopen("test.txt", "r");
if (f)
{
get_name(f);
fclose(f);
}
else
{
printf("Open file failed\n");
}
return 0;
}
If you want to read from the keyboard, read from stdin or use scanf, which internally reads from stdin. If you want to read from a file instead, use FILE *fp, but don't forget to open the file and check if it was successful (you'll find lots of tutorials for this).
Further, when reading in strings, you need an array of characters, not a single one. Note further, that scanf can already deal with formats like "everything that is not a ',' then a ',' then a string. Note that format "[^,]" means "any character except a ',':
So you could adapt the code as follows:
#define LINESIZE 1024
int main(void){
char line[LINESIZE];
char first[LINESIZE];
char last[LINESIZE];
while(fgets(line,LINESIZE,stdin)) {
if(sscanf(line,"%[^,],%s",last,first)==2) {
printf("Read in %s ... %s\n",last,first);
}
else {
printf("Please enter first name a comma and then last name");
}
}
return 0;
}
And if your professor is picky concerning the "use FILE*", you could write:
FILE *fp = stdin;
...
while(fgets(line,LINESIZE,fp)) {
...

Print out first line of input file char by char, but nothing comes to screen

So Im trying to print out the first line of a file thats being passed in lets say its a plain text file with a couple of words in the first line.
I open the file and pass it through a function that does some work on the file called process. This little bit of work if for debugging reason , because my ultimate goal is to read in the entire text file line my line and process each line and reverse the words in that line.
But im stuck here i run the program with a text file argument and i get nothing in return and i know my logic sounds right i think? I just want this to ultimately printout every character in that line. Then eventually put all those characters in a char array or char instream[500]
Can someone tell me what iam doing wrong?
#include <stdio.h>
#include <stdlib.h>
void process(FILE *infile);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
printf("argc = %d\n",argc);
for(i = 1 ; i <= argc; i++)
{
fp = fopen(argv[i], "r");
if(fp == NULL)
{
printf("The file: %s doesnt exist.\n", argv[i]);
}
else
{
printf("The file: %s does exist \n",argv[i]);
process(fp);
}
}
return 0;
}
void process(FILE *infile)
{
int k =0;
char iochar;
char instream[500];
while((iochar = getc(infile)) != '\n')
{
printf("Hi there %c", iochar ); // nothing prints out here why not??
//instream[k++] = iochar;
}
}

Debug Assertion Error in C

got some code here that won't compile correctly because it is saying that my pointer is already null when i am testing for a not null expression in my main function. here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCODE 53
#define MAXMESSAGE 256
void getCode(char *codeIn, char *filename) {
FILE *codeFile;
/* Open the file with the code */
codeFile = fopen(filename, "r");
if (codeFile == NULL) {
printf("Error opening the code file - program terminated\n");
exit(1);
}
/* Read the first (and assumed only) line from the file */
fgets(codeIn, MAXCODE, codeFile);
/* Terminate the string with /0 */
codeIn[MAXCODE] = '\0';
/* Close the file */
fclose(codeFile);
return;
}
int getMessage(int *message, char *filename) {
FILE *messageFile;
int counter = 0;
/* Open the file with the message */
messageFile = fopen(filename, "r");
if (messageFile == NULL) {
printf("Error opening the message file - program terminated\n");
exit(1);
}
/* Read one number at a time from the file and store it */
while (!feof (messageFile))
{
fscanf (messageFile, "%d", (message+counter));
counter++;
}
/* Close the file */
fclose(messageFile);
return (counter);
}
void sortMessage(int *message, int size) {
int i, j, temp;
for (i=0; i<size-1; i++) {
for (j=i; j<size; j++) {
if (message[i]>message[j]) {
temp = message[i];
message[i] = message[j];
message[j] = temp;
}
}
}
return;
}
void decodeMessage(char *codeIn, int *message, int size) {
FILE *outputFile;
int i = 0;
/* Open the output file */
outputFile = fopen("csis.txt", "w");
if (outputFile == NULL) {
printf("Error opening the output file - program terminated\n");
exit(1);
}
for (i=0; i< size; i++) {
fprintf(outputFile, "%c", codeIn[message[i]%100]);
printf("%c", codeIn[message[i]%100]);
}
printf("\n");
/* Close the file */
fclose(outputFile);
return;
}
int main(int argc, char *argv[])
{
char code[MAXCODE];
int msg[MAXMESSAGE];
int msgSize;
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
}
getCode(code, argv[1]);
msgSize = getMessage(msg, argv[2]);
sortMessage(msg, msgSize);
decodeMessage(code, msg, msgSize);
return;
}
So basically my code is using two files called codefile.txt and msgfile.txt to decode the secret message and write the decoded sequence to a new text file called csis.
As woolstar pointed out in the comments, you don't need to NUL terminate your codeIn array following fgets, because fgets will do that for you. In fact, this constitutes an overflow which we can best see by considering what happens when MAXCODE is 1: codeIn contains only one element: codeIn[0], and accessing codeIn[1] is an error.
Similarly, since MAXCODE is 53 and that's how many elements pointed to by codeIn, codeIn[message[i]%100] is suspicious because there's a potential for message[i]%100 to be an invalid index. While we're on this note, it might be wise to make message[i] an unsigned int so that it can't be negative. The format specifier (for printf and scanf) corresponding to unsigned int is %u.
while ( !feof(messageFile) ) is wrong because the EOF flag isn't set until an attempt is made at reading. Between attempting to read and your EOF test, however, you've incremented counter which means you've counted one too many items. Perhaps your loop should look like this:
while (fscanf(messageFile, "%d", (message+counter)) == 1)
{
counter++;
}
Note that this code assumes you've chosen to keep message[i] as an int. If you've chosen to use unsigned int instead, of course you'll want to use the %u format specifier.
You can probably see that feof is mostly superfluous... You can usually test for erroneous reads by checking the return value. Try to avoid feof in the future.
Your main function has a return type of int, yet at the end of it you have a return; statement which doesn't return an int value. Remove that. It's probably causing errors during compilation.
Presumably, when argv != 3 you want to return from main so you don't end up processing invalid arguments... Make sure you return an int value, e.g.
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
return 0;
}

Resources