Passing a filepath to fopen from an Array Fails in C - c

I have a two filepaths input by the user and stored in an array. However, when I try to use one of these filepaths to open a file using fopen the code exits as if the file does not exist. If I hard code the filepath into the fopen function eveything proceeds perfectly.
For Example:
//Libraries
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//Global Functions
//Main Function
int main()
{
//Local Variables
char * user_input_full = NULL;
char user_input = 'a';
size_t len = 0; //Pointer for user_input_full
int size = 0; //Length of the input_use_full array
char *input_array[2]; //This hold the filepaths
int i=0; //A loop counter
//Carve out an initial array for the use input string (it is of unknown length)
user_input_full = calloc(16,sizeof(char));
size = 16;
//Take user input until a newline is encountered.
while(user_input != '\n')
{
scanf("%c", &user_input);
user_input_full[len] = user_input;
len = len+1;
if(len==size)
{
#ifdef DEBUG_MODE
printf("The input stream is being reallocated\n");
#endif
user_input_full = realloc(user_input_full,sizeof(char)*(size+16));
if(user_input_full == NULL)
{
//realloc failed, return a fail status
printf("Realloc of the input stream failed.\n");
return EXIT_FAILURE;
}
}
}
user_input_full[len] = '\0';
#ifdef DEBUG_MODE
printf("The user input was: %s \n", user_input_full);
#endif
//Parse out the file streams
input_array[i] = strtok(user_input_full," ");
while(input_array[i]!=NULL)
{
input_array[++i] = strtok(NULL," ");
}
#ifdef DEBUG_MODE
printf("Input array Values:\n");
for (i=0;i<2;i++)
{
printf("%s \n",input_array[i]);
}
#endif
//open the file specified in input_array[0]
if(fopen(input_array[0],"r") == NULL)
{
printf("Open of the input file failed.\n");
printf("Tried to open: %s ", input_array[0]);
return EXIT_FAILURE;
}
else
{
printf("The file opened.\n");
}
return EXIT_SUCCESS;
}
Would print the error block. However:
//Open the file specified in array[0]
if(fopen("test.txt","r") == NULL)
{
printf("Failed to open the input file.\n");
return EXIT_FAILURE;
}
else
{
printf("The file opened.\n");
}
Works perfectly fine.
I also tried passing the value in input_array[0] to a const char*, but that did not work either. I feel like I am missing some fundamental concept here.
EDIT: Clarified one of the comments in the code block

The real reason it is failing is due to trailing newline in the filename. All you need is to add newline as string token.
Change this line:
input_array[i] = strtok(user_input_full," ");
to:
input_array[i] = strtok(user_input_full," \n");
and this line:
input_array[++i] = strtok(NULL," ");
to:
input_array[++i] = strtok(NULL," \n");
This will remove the trailing newlines.

First mistake I note is in the following code block. it's inputing 3 three strings to input_array and going out of bound.
//Parse out the file streams
input_array[i] = strtok(user_input_full," ");
while(input_array[i]!=NULL)
{
input_array[++i] = strtok(NULL," ");
}
Change this code block to something as shown here.
input_array[i] = strtok(user_input_full," ");
for(i=1;i<2;i++)
{
input_array[i] = strtok(NULL," ");
}

Related

C Unions with Files and buffer overflow?

My program loads/saves double value into a text file using union.
I think I am having a buffer overflow, when I use fflush(stdin) it works, but I can't. The problem maybe somewhere else though. The code jumps without letting me enter a file to load from ( 2.000000 is autoinserted ).
Ps. Yes I know that tab[i] would be better than *(tab+i) but spare me, I just have to do it like this.
output :
Enter double value:8794.061758
Enter path to file you wish to save:valleykingstopwantreachspellshipcontinue
File saved
Enter a path to file you wish to load: 2.000000 ----- This value is inserted automatically ( I didnt write it)
Process finished with exit code 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
union double_to_char_t
{
double d;
char bytes[8];
};
int save_double(const union double_to_char_t *dtc, const char *filename)
{
if(dtc == NULL || filename == NULL) return 1;
FILE * f=fopen(filename,"w");
if(f == NULL) return 2;
int result = fwrite(dtc, sizeof(dtc), 1, f);
if( result != 1)
{
fclose(f);
return 3;
}
fclose(f);
return 0;
}
int load_double(union double_to_char_t *dtc, const char *filename)
{
if( dtc == NULL || filename == NULL) return 1;
FILE * f = fopen(filename,"r");
if( f == NULL ) return 2;
int result = fread(dtc, sizeof(dtc), 1, f);
if( result != 1)
{
fclose(f);
return 3;
}
fclose(f);
return 0;
}
int main()
{
union double_to_char_t unia;
char temp1[40] = {0};
char temp2[40] = {0};
char *input1 = temp1;
char *input2 = temp2;
printf("Enter double value: ");
if(scanf(" %lf",&(unia.d))!=1)
{
printf("Incorrect input");
exit(1);
}
printf("Enter path to file you wish to save:");
fgets(input1, 40, stdin);
int wynik = save_double(&unia,input1);
if(wynik > 0)
{
printf("Couldn't create file\n");
exit(5);
}
else
{
printf("File saved\n");
}
printf("Enter a path to file you wish to load: ");
fgets(input2, 40, stdin);
// scanf(" %39[^\n]", input2);
int score = load_double(&unia,input2);
if(score > 0 && score < 3)
{
printf("Couldn't open file\n");
exit(4);
}
if(score == 3)
{
printf("File corrupted\n");
exit(6);
}
printf("%f",unia.d);
return 0;
}
You used %39[^\n] to read the filename, then typed a 40 character filename. The first 39 characters were put into input1, and the last character was left in the input stream.
When you then tried to get the filename for input2, it read that last character. That's why it didn't wait for you to type anything -- there was still input available after the first filename was read.
So you saved to valleykingstopwantreachspellshipcontinu and loaded from e.
You need to ensure that your input buffer is longer than any potential input. If you use fgets() instead of scanf(), you can test whether the input ends with a newline. If not, you can report that the input was too long, read characters until the newline, then ask for input again. (The non-standard fflush(stdin) discards everything up to the next newline, which is why adding that fixed the problem.)
if (!fgets(input1, 40, stdin)) {
printf("input error\n");
exit(1);
}
if (input1[strlen(input1)-1] != '\n') { // check for trailing newline
printf("filename too long\n);
exit(3);
}
input1[strlen(input1)-1] = '\0'; // remove it before using as filename
You could also use the getline() function. This isn't standard C, but it's POSIX and widely implemented. It allocates the input buffer dynamically so any length can be accomodated.

C program not writing to file?

My program won't write to the file after input is received. Everything else seems to work as expected.
Where have I gone wrong?
#include <stdio.h>
#include <unistd.h>
int main()
{
char fileSelectionInput[20];
printf("Select a file to print to: ");
gets(fileSelectionInput);
if (access(fileSelectionInput, F_OK ) == -1) {
puts("It seems that this file does not exist, sorry.");
return 0;
}
printf("Okay now you can type text to append\n\n");
FILE* testFile = fopen(fileSelectionInput, "w+");
int writesLeft = 10;
while (writesLeft > 1)
{
char textInput[50];
gets(textInput);
fputs(textInput, testFile);
writesLeft--;
}
fclose(testFile);
return 0;
}
The problem is basically the use of gets.
Try this changes bellow where I used scanf and fgets:
#include <stdio.h>
// #include <unistd.h>
int main() {
char fileSelectionInput[20];
printf("Select a file to print to: ");
scanf("%19s", fileSelectionInput); // %19s checks the size of input
// if (access(fileSelectionInput, F_OK ) == -1) {
// puts("It seems that this file does not exist, sorry.");
// return 0;
// }
printf("Okay now you can type text to append\n\n");
FILE* testFile = fopen(fileSelectionInput, "a+");
if (testFile == NULL) {
perror("fopen()");
return 1;
}
int writesLeft = 10;
while (writesLeft > 1) {
char textInput[50];
fgets(textInput, sizeof(textInput), stdin);
fputs(textInput, testFile);
--writesLeft;
}
fclose(testFile);
return 0;
}
When you check the result of fopen, you don't have to check if the file exists with access. This makes your code more portable.
I used %19s in scanf so it won't write past the bounds of the array; 19 characters and 1 null byte fit into it.

My program not work as expected

I need to find the position of some strings. These strings are stored in a file named queryfile , from an other file named datafile.
However, my program does not work as expected.
Can some one help me?
My program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *queryfile;
queryfile = fopen("op2query.txt","r");
FILE *datafile;
datafile = fopen("op2data.txt","r" );
int i = 1;
char word[99];
char search[99];
if(queryfile==NULL) {
printf("Error in reading Query File");
exit(1);
}
if(datafile==NULL) {
printf("Error in reading Data File");
exit(1);
}
while(fscanf(queryfile,"%98s",search)==1){
while(fscanf(datafile,"%98s",word)==1){
if (strcmp(word,search)==0){
printf("\n %i %s ", i, search);
rewind(datafile);
i=1;
break;
}
else
i++;
}
}
fclose(datafile);
fclose(queryfile);
return 0;
}
I build an array of each set of words to be tested, by splitting the query string into words. These words can span a line break in the data file. I mark the data file position on the second word of the set, if the search fails I seek to that point (if necessary). The program succeeds even if I duplicate every word "age" in the data file.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXWORDS 5
#define MAXLEN 99
int main()
{
int j, i, done, words, count;
long mark;
char word[MAXLEN];
char search[MAXLEN];
char *tok, *sptr[MAXWORDS];
FILE *queryfile;
FILE *datafile;
if ((queryfile = fopen("op2query.txt","r")) == NULL) {
printf("Error in reading Query File");
exit(1);
}
if ((datafile = fopen("op2data.txt","r" )) == NULL) {
printf("Error in reading Data File");
exit(1);
}
while(fgets(search, MAXLEN, queryfile) != NULL){
words = 0;
done = 0;
count = 0;
mark = -1;
tok = strtok(search, " \r\n");
while (tok && words < MAXWORDS) { // build array of query
sptr[words++] = tok;
tok = strtok(NULL, " \r\n"); // strips newline too
}
if (words < 1) // no more queries
break;
rewind(datafile); // beginning of file
while (!done) { // until none to read
count++;
if (mark >= 0) // when more than one word to search
fseek (datafile, mark, SEEK_SET);
mark = -1;
for (j=0; j<words; j++) {
if (j == 1) // mark for next search
mark = ftell(datafile);
if (fscanf(datafile, "%98s", word) != 1){
done = 1; // end of file
break;
}
if (strcmp(sptr[j], word)!=0)
break; // failed multi word search
}
if (done)
printf("NOT FOUND!");
else if (j == words) { // if all words found
printf("%d", count);
done = 1; // success
}
}
for (i=0; i<words; i++)
printf(" %s", sptr[i]); // show array of words asked
printf("\n");
}
fclose(datafile);
fclose(queryfile);
return 0;
}
Program output:
18 wisdom
40 season
NOT FOUND! summer
22 age of foolishness
UPDATE - I print NOT FOUND! when query not found. Added "summer" to query file.
you should put some debug-output behind the fscanf-calls (like printf("search:<%s> word:<%s>", search, word);
Then you will see, that fscanf stops at finding a white-space. you compare wisdom to each consecutive word in op2data.txt.
You should read line by line with fgets() removing the CR/LF from search.
But be aware, that the multi-word-search-word in data-file may be split between lines. like:
find me
i am the text to find
me in this file
so a better solution would be:
read search word by line (remove CR/LF) (normalize it by removing double spaces and not-letters)
read a chunk from datafile and normalize it too.
compare or continue by moving the read-position in data left by length of length of search word

Word palindrome in C

My task is to find word palindromes in a text file and to NOT print them into results file. The results file should only contain all the spaces and words that are NOT palindromes. I've been working on this program for two solid weeks, but as I am a total newb in C, I can't simply imagine how to do this correctly. Also, I have to work in Linux environent, so I can't use commands like strrev() which would make my life a lot easier at this point...
Anyways, data file contains a lot of words in a lot of lines separated by quite a few spaces.
Here is the program that is working, but doesn't work with any spaces, because I don't know how to check them at the needed place.
#include <stdio.h>
#include <string.h>
const int CMAX = 1000;
const int Dydis = 256;
FILE *dataFile;
FILE *resFile;
void palindrome(char *linex);
int main(){
char duom[CMAX], res[CMAX], linex[Dydis];
printf("What's the name of data file? \n");
scanf("%s", duom);
dataFile=fopen(duom, "r");
if (dataFile==NULL){
printf ("Error opening data file \n");
return 0;
};
printf("What's the name of results file? \n");
scanf ("%s", res);
resFile=fopen(res, "w");
if (resFile==NULL){
printf ("Error opening results file \n");
return 0;
};
while (fgets(linex, sizeof(linex), dataFile)) {
palindrome(linex);
}
printf ("all done!");
fclose(dataFile);
fclose(resFile);
}
void palindrome(char *linex){
int i, wordlenght, j;
j = 0;
char *wordie;
const char space[2] = " ";
wordie = strtok(linex, space);
while ( wordie != NULL ) {
wordlenght = strlen(wordie);
if (wordie[j] == wordie[wordlenght-1]) {
for (i = 0; i < strlen(wordie); i++) {
if (wordie[i] == wordie[wordlenght-1]) {
if (i == strlen(wordie)-1) {
fprintf(resFile,"");
}
wordlenght--;
}
else {
fprintf(resFile,"%s", wordie);
break;
}
}
}
else {
fprintf(resFile,"%s", wordie);
}
wordie = strtok(NULL, space);
}
}
EDIT:
Code below works as following:
input file is read char by char
if char read isn't alphanumeric, then it is written to the output file
else, the whole word is read with fscanf
if word is not a palindrome, then write to the output file
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int is_pal(char* word) {
size_t len = strlen(word);
char* begin = word;
char* end = word + len - 1;
if (len == 1) {
return 1;
}
while (begin <= end) {
if (*begin != *end) {
return 0;
}
begin++;
end--;
}
return 1;
}
int main(void)
{
FILE* fin = fopen("pals.txt", "r");
if (fin == NULL) {
perror("fopen");
exit(1);
}
FILE* fout = fopen("out_pals.txt", "w");
if (fout == NULL) {
perror("fopen");
exit(1);
}
int ret;
char word[100];
while ((ret = fgetc(fin)) != EOF) {
if (!isalpha(ret)) {
fprintf(fout, "%c", ret);
}
else {
ungetc(ret, fin);
fscanf(fin, "%s", word);
if (!is_pal(word)) {
fprintf(fout, "%s", word);
}
}
}
fclose(fin);
fclose(fout);
return 0;
}
I've created file with following content:
cancer kajak anna sam truck
test1 abc abdcgf groove void
xyz annabelle ponton belowoleb thing
cooc ringnir
The output file :
cancer sam truck
test1 abc abdcgf groove void
xyz annabelle ponton thing
(line with two spaces)
As you can see, the number of spaces between words are the same as in the input file.
I've assumed that single word could have 100 chars maximum. If there would be longer words, reading with fscanf onto fixed-size buffer can be harmful.
Hints:
strtok() gives you a pointer to the start of delimited words but it does not
extract them or put them in their own string for you.
You need some logic to find the end of each word. The function
strlen() will tell you how many characters there are from the char*
that it gets until a null-character. If you give it a pointer to the start
of a word within a sentence it will give you the length from the start of the
word to the end of the sentence.
Breaking palindrome() into a function that loops over words in a line and a
function that returns whether or not a single word is a palindrome
may help.
Your for loop is checking each pair of letters twice. i only needs to scan over half
of the word length.
You only need a single if within palindrome(). I'm not sure why you have so many.
They're redundant.

Writing string to text file in C (extra blank space in the beginning of file)

I have a problem with writing a string to text file and reading it from file.
Input string (char text1) writes to the file (input.txt) correctly and reads too.
But I have a problem with the result file - the string seems to write to file correctly, but if I take a look at file, there is a blank space before the result string in file at the beginning. If I input text "weather is weather" then in the result file I have this -
"weather is is weather". The result string text is ok, the only problem is that for some reason, there is a blank space at the beginning of the result file.
When I print the contents of result file on the screen with this code
while((ch2 = fgetc(result)) != EOF)
printf("%c", ch2);
it prints nothing, but if I print the text2 string itself (not from file) with puts(text2); then it prints correctly.
What could be the cause of this problem and how could I solve it?
Here's the whole program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char text1[200], text2[200], words[20][100], *dist, ch1, ch2;
int i, j, nwords=0;
FILE *input, *result;
input = fopen("input.txt", "w");
if(input == NULL)
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
// Text input
printf("\n Enter the text:\n\n ");
gets(text1);
fputs(text1, input);
fclose(input);
// Split string into words
dist = strtok(text1, " ,.!?");
i=0;
while(dist!=0)
{
strcpy(words[i],dist);
dist = strtok(NULL, " ,.!?");
i++;
nwords++;
}
// Duplicating words that doesn't repeat in input string and copy them into tex2 string
int flag_arr[20];
memset(flag_arr, 0, 20);
for(i=0; i <= nwords-1; i++)
{
for(j=0; j<=nwords-1; j++)
{
if(strcmp(words[i],words[j])==0)
{
flag_arr[i] += 1;
}
}
}
for(i = 0; i <=nwords-1; i++)
{
if(flag_arr[i] > 1)
{
strcat(text2," ");
strcat(text2,words[i]);
}
else
{
strcat(text2," ");
strcat(text2,words[i]);
strcat(text2," ");
strcat(text2,words[i]);
}
}
result = fopen("result.txt", "w");
if(result == NULL)
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
fputs(text2, result);
fclose(result);
// Rezultats
fopen("input.txt", "r");
if(input == NULL)
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
fopen("result.txt", "r");
if(result == NULL)
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
printf("\n\n\n Input:\n\n ");
while((ch1 = fgetc(input)) != EOF)
printf("%c", ch1);
// puts(input);
printf("\n\n\n Result:\n\n ");
while((ch2 = fgetc(result)) != EOF)
printf("%c", ch2);
// puts(text2);
fclose(input);
fclose(result);
getchar();
return 0;
}
It's because stdout is buffered. Either add a newline to your printing, or explicitly flush the buffer with
fflush(stdout);
You have this line
input = fopen("input.txt", "w");
And this line (two times, once is enough)
fopen("input.txt", "r");
Nowhere do you actually reassign the input variable. This means that when you attempt to read from input you will get an error (which you do not report) as you try to read from a write-only file handle.
Regarding your statement: then in the result file I have this - "weather is is weather".
In this block:
else
{
strcat(text2," ");
strcat(text2,words[i]);
strcat(text2," ");
strcat(text2,words[i]); //(change this to strcat(text2,words[i+1]);)
}
It looks like you are not incrementing i, and so will get the same word twice, separated by a space, " ".
By the way, this suggests that your file is fine, rather it is the way you are presenting the buffers after having extracted them that's the problem.
I realize the original problem is quite old, however I found the advice lacking and wanted to leave behind something more useful for understanding....
The most important issue with your program is one that the other programmers did not address. You must initialize text2.
You used strcat with text2 without first initializing text2. In other words you concatenated the contents of your pointer with text2, but text2 never had any value, so what was printed to screen (or file) was left over garbage.
The fact that your program worked after flushing has little to do with flushing but rather the random effects of memory.
char text1[20] = "";
char text2[20] = "";
Solves half the problem. The other issue is minor regarding when to put the spaces between words.
for(i = 0; i <=nwords-1; i++)
{
if(flag_arr[i] > 1)
{
strcat(text2,words[i]); // Check out the ordering here.
strcat(text2," ");
}
else
{
strcat(text2,words[i]);
strcat(text2," ");
strcat(text2,words[i]);
strcat(text2," ");
}
}

Resources