I have to make a function which reads a file line by line and copies a some of them to another file. The head of the function has to look like this: "int write_x(const char *input_path, const char *output_path, int x)" and can't be changed. For example if x = 3 every third line of the input txt-file should be copied to the output txt-file. Every line has a maximum of 80 signs. I hope someone can help me because i'm not programming very long yet.
This is what I have alreaday, but it doesn't work:
#include <stdlib.h>
#include <stdio.h>
int write_x(const char *input_path, const char *output_path, int x){
input_path = "in.txt";
output_path = "out.txt";
FILE *in
FILE *out
char text[100];
for(int i = 0; i < 100; i++){
fgets(text[i], 80, in);
if(i % x == 0) {
fprintf(out, "%s\n", text[i]);
}
}
return 0;
}
I didn't compile it (I'll leave that to you), but how about something like this?
Note that if your teacher penalizes for the use of 'goto', then you'll need to modify the error handling.
#include <stdio.h>
#include <stdlib.h>
int write_x(const char *input_path, const char *output_path, int x) {
int result = 0 ;
FILE * inputFile=NULL;
FILE * outputFile=NULL;
/* Open the input file for reading */
inputFile = fopen( input_path, "r" ) ;
if ( inputFile == NULL ) {
perror( "fopen(input_path)" ) ;
result = -1;
goto clean_up;
}
/* Open the output file for writing */
outputFile = fopen( output_path, "w") ;
if ( outputFile == NULL ) {
perror( "fopen(output_path)" ) ;
result = -1;
goto clean_up;
}
int lineNumber = 0 ;
char * lineBuffer = NULL ; // memory will be allocated by getline()... but you'll need to free it up afterwards
int lenBuffer ; // getline will set how bug the buffer is
/* Repeat for each line read */
while (getline( &lineBuffer, &lenBuffer, inputFile) != -1) {
/* Only at each 'x' line count */
if ( (++lineNumber % x ) == 0 ) {
/* Write the line to the output file */
if ( fwrite( lineBuffer, lenBuffer, 1, outputFile ) != lenBuffer ) {
perror("fwrite");
result = -1;
goto clean_up;
}
}
}
clean_up:
/* avoid memory leak */
if ( lineBuffer != NULL ) {
free( lineBuffer ) ;
}
/* Close the input file */
if ( inputFile != NULL ) {
fclose( inputFile ) ;
}
/* Close the output file */
if ( outputFile != NULL ) {
fclose( outputFile ) ;
}
/* All done */
return result ;
}
It seems like a really bad design to be passing paths to this function as arguments instead of FILE *'s, but you're under no obligation to read the file line by line. Just read one character at a time. Something like:
#include <stdlib.h>
#include <stdio.h>
FILE * xfopen(const char *path, const char *mode);
int
write_x(const char *input_path, const char *output_path, int x)
{
FILE *in = xfopen(input_path, "r");
FILE *out = xfopen(output_path, "w");
int c;
int count = 1;
while( (c = fgetc(in)) != EOF ){
if( count == x ){
fputc(c, out);
}
if( c == '\n' ){
count = ( count % x ) + 1;
}
}
return 0;
}
int
main(int argc, char **argv)
{
int step = argc > 1 ? strtol(argv[1], NULL, 10) : 1;
char *in = argc > 2 ? argv[2] : "in.txt";
char *out = argc > 3 ? argv[3] : "out.txt";
write_x(in, out, step);
return 0;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
Related
Get specific content from a file and store it in a variable. So far I get that I can convert the file content into a string. But I'm not sure how can I 'extract' the content from the string I converted and would like some help.
The original file looks something like this:
XXXXXX
XXXXX
Addr = 12:23:34:45:45
XXX
XXX
I need to extract and store the Addr as a string. Want to look for the prefix Addr = and just copy it into a buffer. But I don't know how can I do it...
So far my code looks like below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
//So far I'm looking for it using the MAC addr format
const char *get_mac_addr(char *str, char *dest) {
if (str == NULL)
return 0;
char *start = NULL;
int token_count = 0;
char *ptr = str;
if (*ptr && *(ptr + 1)) // skip two chars in the beginning of the string
ptr += 2;
else
return 0;
while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') {
if (token_count == 5)
break;
/* if ':' found and previous two characters are hexidecimal digits then
the substring could be part of MAC
*/
if (*ptr == ':' && isxdigit(*(ptr - 1)) && isxdigit(*(ptr - 2))) {
token_count++;
if (start == NULL)
start = ptr - 2;
int i = 0;
while (*ptr != '\0' && i++ < 3)
ptr++;
} else {
start = NULL;
token_count = 0;
ptr++;
}
}
strcpy(dest, start);
return dest;
}
const char *file2str(){
/* declare a file pointer */
FILE *infile;
char *buffer;
long numbytes;
char dest[18];
/* open an existing file for reading */
infile = fopen("~/Desktop/file.config", "r");
/* quit if the file does not exist */
//if (infile == NULL)
// return 1;
/* Get the number of bytes */
fseek(infile, 0L, SEEK_END);
numbytes = ftell(infile);
/* reset the file position indicator to
the beginning of the file */
fseek(infile, 0L, SEEK_SET);
/* grab sufficient memory for the
buffer to hold the text */
buffer = (char *)calloc(numbytes, sizeof(char));
/* memory error */
//if(buffer == NULL)
// return 1;
/* copy all the text into the buffer */
fread(buffer, sizeof(char), numbytes, infile);
fclose(infile);
/* confirm we have read the file by
outputing it to the console */
printf("The file called test.dat contains this text\n\n%s", buffer);
//memset(dest, '/0', sizeof(dest));
get_mac_addr(buffer, dest);
/* free the memory we used for the buffer */
//free(buffer);
printf("Dest is \n\n%s", dest);
return dest;
}
int main() {
printf(file2str);
return 0;
}
I really appreciate your help. Please bare with me as I'm not very good at c programming. I would like to convert the main function into one function so I can directly call it and return a string. I converted the main function as following, but I'm not sure why when I print it, there is nothing show up:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
const char *MACadd()
{
char buf[256];
char *addr = NULL;
FILE *in = xfopen("~Desktop/file.config", "r");
while( fgets(buf, sizeof buf, in) ){
addr = strstr(buf, "Addr = ");
if( addr && addr < buf + sizeof buf - ADDRLEN){
addr += strlen("Addr = ");
addr[ADDRLEN] = '\0';
break;
}
}
//printf("addr = %s\n", addr);
return addr;
}
FILE *xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int main(){
printf("%s", MACadd());
return 0;
}
You could read the file line by line with the fgets function and use the sscanf function to extract the relevant portion like that:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define ISXDGT(c) isxdigit((unsigned char)(c))
static bool is_macaddr (const char *s)
{
return ISXDGT(s[0]) && ISXDGT(s[1]) && s[2] == ':'
&& ISXDGT(s[3]) && ISXDGT(s[4]) && s[5] == ':'
&& ISXDGT(s[6]) && ISXDGT(s[7]) && s[8] == ':'
&& ISXDGT(s[9]) && ISXDGT(s[10]) && s[11] == ':'
&& ISXDGT(s[12]) && ISXDGT(s[13]) && s[14] == ':'
&& ISXDGT(s[15]) && ISXDGT(s[16]);
}
bool get_macaddr_from_file (const char *filename, char *macaddr)
{
char line[4096];
bool done = false;
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open the file '%s'\n", filename);
return false;
}
while (fgets(line, sizeof line, fp) != NULL) {
/* Modify the prefix (" Addr = " here) at your convenience */
if (sscanf(line, " Addr = %17s", macaddr) == 1 && is_macaddr(macaddr)) {
done = true;
break;
}
}
fclose(fp);
return done;
}
int main (void)
{
char macaddr[18];
if (get_macaddr_from_file("file.conf", macaddr)) {
printf("MAC: %s\n", macaddr);
}
}
char *extract(const char *str, char *buff)
{
char *addr = strstr(str, "Addr");
if(addr)
{
addr += sizeof("Addr") - 1;
while(!isdigit((unsigned char)*addr))
{
if(*addr == '\n' || !*addr)
{
addr = NULL;
break;
}
addr++;
}
if(addr)
{
while(*addr && *addr != '\n' && (isdigit(*addr) || *addr == ':'))
{
*buff++ = *addr++;
}
*buff = 0;
}
}
return addr ? buff : NULL;
}
void main(int argc, char** argv)
{
char *str = "XXXXXX\nXXXXX\n\nAddr = 12:23:234:145:45 \nXXX\nXXX\n";
char mac[30];
if(extract(str,mac)) printf("Hurray!!! `%s`\n", mac);
else printf("MIsareble failure\n");
}
https://godbolt.org/z/6TjK8b
This gets a little tricky if you don't want to restrict yourself to a fixed maximum line length, but it's probably sufficient to do something like:
#define ADDRLEN 14
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
int
main(int argc, char **argv)
{
char buf[256];
char *addr = NULL;
FILE *in = xfopen(argc > 1 ? argv[1] : "-", "r");
while( fgets(buf, sizeof buf, in) ){
addr = strstr(buf, "Addr = ");
if( addr && addr < buf + sizeof buf - ADDRLEN){
addr += strlen("Addr = ");
addr[ADDRLEN] = '\0';
break;
}
}
printf("addr = %s\n", addr);
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
To break this into a function, you need to be a little bit careful. In your attempt, you've passed back references to local variables which cease to exist after the function returns. Perhaps you want something like:
#define ADDRLEN 14
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * xfopen(const char *path, const char *mode);
const char *
MACadd(const char *path, char *buf, size_t s)
{
char *addr = NULL;
FILE *in = xfopen(path, "r");
while( fgets(buf, s, in) ){
addr = strstr(buf, "Addr = ");
if( addr && addr < buf + s - ADDRLEN){
addr += strlen("Addr = ");
addr[ADDRLEN] = '\0';
break;
}
}
return addr;
}
FILE *xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(void)
{
char buf[256];
printf("%s", MACadd("input", buf, sizeof buf));
return 0;
}
I think that is easier than you are doing, once you moved the file contnent in a string, use strstr() - here ther is the description http://www.cplusplus.com/reference/cstring/strstr/ - to find "addr = " and then get the string from there to the character "\n"
follow this example
#include<string.h>
#include<stdio.h>
#define endchrptr(ptr1, ptr2, ptr3) (ptr1 < ptr2 ? (ptr1<ptr3?ptr1:ptr3) : (ptr2<ptr3?ptr2:ptr3))
bool get_mac_addr(const char* source, char *dest) {
if(source!=NULL&&dest!=NULL) {
char* addr_pointer=strstr(source, "Addr = ")+7;//find where the address start
char* end_addr_pointer=endchrptr(strchr(addr_pointer, '\n'), strchr(addr_pointer, '\r'), strchr(addr_pointer, '\0'));//find where the address ends
if(end_addr!=NULL) {
for(int i=0; i<end_addr_pointer-addr_pointer; ++i) {//copy the address
dest[i]=addr_pointer[i];
}
dest[end_addr_pointer-addr_pointer],
}
else return false;
}
else return false;
}
int main()
{
char *str = "XXXXXX\nXXXXX\n\nAddr = 12:23:234:145:45 \nXXX\nXXX\n";
char mac[30];
get_mac_addr(str, mac);
printf("%s", mac);
}
I just tried in DevC++ and it works.
Let me know if it works.
There are multiple problems in the code:
fopen("~/Desktop/file.config", "r"); will fail because the ~ in the filename is not expanded to the home directory by fopen, it is a feature of the command shell. Use the full path instead, or take the filename as an argument.
you do not check for fopen() failure: passing a null stream pointer to fseek has undefined behavior and will probably crash the program.
printf(file2str); is a major mistake: you try to use the bytes from the function as a format string, you will get garbage output and possibly a crash because of undefined behavior. Use printf("%s\n", file2str()); instead.
there is no need to read the whole file in memory at once for this problem, just reading one line at a time is much simpler. Furthermore, you do not allocate enough memory for the null terminator, so you get undefined behavior with using buffer as a C string.
get_mac_addr is way too complicated: you could use strstr to locate the string "Addr = " and extract the following word.
Here is a simpler version:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
const char *get_mac_address(const char *str, char *dest) {
if (!strncmp(buf, "Addr = ", 7)) {
const char *p = buf + 7;
for (i = 0; i < 17; i++) {
if (i % 3 == 2) {
if (p[i] != ':')
break;
} else {
if (!isxdigit((unsigned char)p[i]))
break;
}
}
if (i == 17 && !isalnum((unsigned char)p[i]) {
memcpy(dest, p, 17);
dest[17] = '\0';
return dest;
}
}
return NULL;
}
int main() {
char buf[256];
char address[20];
FILE *fp = fopen("/home/ImTrying/Desktop/file.config", "r");
if (fp != NULL) {
while (fgets(fp, buf, sizeof buf)) {
if (get_mac_address(buf, address)) {
printf("Dest is %s\n", address);
break;
}
}
fclose(fp);
}
return 0;
}
For my algorithm, I would like to backtrack after going through all the chars in a file back to specific index char. For example, I have a file with ABCDEF, I want to access in the order ABCDEF then BCDEF then CDEF and so on. Is there a way I can do that with just fgetc and no string buffer?
FILE *file = fopen("temp.txt", "r");
int c;
while (1) {
c = fgetc(file);
if (feof(file)) {
break;
}
// Access and print char
}
You'll probably want to handle edge cases and error more cleanly than this, but...:
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
int c;
long offset = 0;
FILE *ifp = argc > 1 ? xfopen(argv[1], "r") : stdin;
while( fseek(ifp, offset++, SEEK_SET) == 0 ) {
while( (c = fgetc(ifp)) != EOF ) {
putchar(c);
}
if( ferror(ifp) ) {
return EXIT_FAILURE;
}
if( offset == ftell(ifp) ) {
break;
}
}
return EXIT_SUCCESS;
}
I'm writing a program said in this post title. I take reference at this webpage.
https://www.includehelp.com/c-programs/c-program-to-print-given-number-of-lines-of-a-file-like-head-command-in-linux.aspx
Here are the codes from that webpage.
#include <stdio.h>
int main(int argc, char * argv[])
{
FILE *fp; // file pointer
char *line = NULL;
int len = 0;
int cnt = 0;
if( argc < 3)
{
printf("Insufficient Arguments!!!\n");
printf("Please use \"program-name file-name N\" format.\n");
return -1;
}
// open file
fp = fopen(argv[1],"r");
// checking for file is exist or not
if( fp == NULL )
{
printf("\n%s file can not be opened !!!\n",argv[1]);
return 1;
}
// read lines from file one by one
while (getline(&line, &len, fp) != -1)
{
cnt++;
if ( cnt > atoi(argv[2]) )
break;
printf("%s",line); fflush(stdout);
}
// close file
fclose(fp);
return 0;
}
My problem is the getline function. Since I'm not using Linux that function's giving error in my compiler. I tried to change it to fgets function. This is my revised codes.
I got two errors in the line ' while (fgets(&line, bufferLength, fp) != -1)'.
Error: passing argument 1 of 'fgets' from incompatible pointer type.
Error: comparison between pointer and integer.
My question is - how can I modify the program using fgets? Many thanks to anyone who can work this out.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp; // file pointer
char *line = NULL;
int bufferLength = 255;
int cnt = 0;
if( argc < 3)
{
printf("Insufficient Arguments!!!\n");
printf("Please use \"program-name file-name N\" format.\n");
return -1;
}
// open file
fp = fopen(argv[1],"r");
// checking for file is exist or not
if( fp == NULL )
{
printf("\n%s file can not be opened !!!\n",argv[1]);
return 1;
}
// read lines from file one by one
while (fgets(&line, bufferLength, fp) != -1)
{
cnt++;
if ( cnt > atoi(argv[2]) )
break;
printf("%s",line);
fflush(stdout);
}
// close file
fclose(fp);
return 0;
}
Your program should compile and run correctly follows:
//c program to print given number of lines from beginning of a file
//file name and number of lines must be supply as command line argument
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
FILE* fp; // file pointer
char* line = malloc(255);
int bufferLength = 255;
int cnt = 0;
if( argc < 3)
{
printf("Insufficient Arguments!!!\n");
printf("Please use \"program-name file-name N\" format.\n");
return -1;
}
// open file
fp = fopen(argv[1],"r");
// checking for file is exist or not
if( fp == NULL )
{
printf("\n%s file can not be opened !!!\n",argv[1]);
return 1;
}
// read lines from file one by one
while (fgets(line,bufferLength, fp))
{
cnt++;
if ( cnt > atoi(argv[2]) )
break;
printf("%s",line);
fflush(stdout);
}
// close file
fclose(fp);
free(line);
return 0;
}
we have two main problems, first
char * line = NULL;
line is a line of characters, a string if you want to call it that, so we must reserve enough memory to accommodate a complete line, and we do this with the malloc function, as seen in the program, the other problem we have with fgets, this function returns a pointer therefore we cannot compare the value returned by fgets with an integer, the declaration
while (fgets (line, bufferLength, fp))
is equivalent to running the loop while fgets is other than NULL. Finally we must use line instead of &line, the latter asks for the address of the line pointer, and not the address it points to.
There's no need to keep track of more than a single character. Reading full lines is overkill. Just do:
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
int count = argc > 1 ? strtol(argv[1], NULL, 10) : 1;
FILE *in = argc > 2 ? xfopen(argv[2], "r") : stdin;
int line = 0;
int c;
while( line < count && ( c = fgetc(in)) != EOF ) {
putchar(c);
if( c == '\n' ) {
line += 1;
}
}
}
Note that I've reversed the order of the arguments, so that stdin is read if only a count is given.
i'm trying to fill each row of the array with each word of the file.
I don't want to overallocate memory , so i want to know atleast the lenght of the longest word and the number of rows i should allocate, so the number of words written in the file.
I can't understand where is the problem in the code. I think it should be a problem with counting the longest word since when i print longest_file_word after assigning the value returned by the function it prints -1.
Obviously it doesnt work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int longestWord(char *file, int *nWords);
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen);
int main(int argc, char *argv[]){
int file_elements_number=0 , i , j , k , z , longest_file_word , count_file_words ;
char *filename =(char*)malloc((strlen(argv[2]) +1 )*sizeof(filename));
strcpy( filename , argv[1]);
for(i = 0; i < strlen(argv[1])+1 ; i++){
printf("%c" , filename[i]);
}
if(filename = NULL){
printf("Non c'e' abbastanza memoria");
return 1;
}
if(argc!=2)
{
printf("Errore numero parametri passati da linea di comando\n");
return 1;
}
longest = longestWord( filename , &count);
printf("ciao %d\n%d\n", count , longest);
char **file_words = Create2DStr(count, longest);
FILE *file_ptr;
const char delim[] = {" \n\t"};
char line[260];
char *buf = NULL;
file_ptr = fopen( filename, "r");
count=0;
while(fgets(line, 260, file_ptr))
{
buf = strtok(line, delim);
while(buf)
{
if((strlen(buf) > 0)){
strcpy(file_words[count], buf);
count++;
}
buf = strtok(NULL, delim);
}
}
for(i = 0 ; i < count ; i++){
for( j = 0 ; j < longest ; j++){
printf("%c" , file_words[i][j]);
}
printf("\n");
}
fclose(file_ptr);
free(filename);
filename = NULL;
return 0;
}
int longestWord(char *filename, int *nWords)
{
FILE *file_ptr=0;
int cnt=0, longest=0, numWords=0;
char c;
file_ptr = fopen(filename, "r");
if(file_ptr){
while ( (c = fgetc(file_ptr) ) != EOF )
{
if ( isalnum (c) ) {
cnt++;
}
else if ( ( ispunct (c) ) || ( isspace(c) ) || (c == '\0' ) || (c== '\n'))
{
(cnt > longest) ? (longest = cnt, cnt=0) : (cnt=0);
numWords++;
}
}
*nWords = numWords;
fclose(file_ptr);
}
else {
return -1;
}
return longest;
}
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen){
int i;
char **a = {0};
a =(char**) calloc(numStrings, sizeof(a));
for(i=0;i<numStrings; i++)
{
a[i] = (char*)calloc(maxStrLen + 1, 1);
}
return a;
}
You're doing,
if(filename = NULL)
rather than,
if(filename == NULL)
after reading your filename.
You should be compiling with warnings turned on, -Wall on gcc.
The result -1 means that function longestWord cannot open the specified file name which may be a result of the if(filename = NULL)
Apart from this it is difficult to understand what you are doing with argv[1] and argv[2] to prepare filename. You allocate memory based on the string length of argv[2], then copy the string from argv[1] which could be longer.
You should do the checks of argc and filename before you access argv or filename.
I'm new to C, and I've been trying to figure out pointers.
This program works with -i but segfaults after a few lines and -f segfaults right away.
#include <stdio.h>
#include <string.h>
void search_and_print ( char pattern[], FILE* search_file );
int main ( int argc, char *argv[] ) {
const char TOO_MANY_VARIABLES[] = "Too many arguments from the command line!";
const char NOT_ENOUGH_VARIABLES[] = "\nUSAGE: a.out [-i] [-f filename] (Search Pattern)\n";
if (argc < 2) { printf(NOT_ENOUGH_VARIABLES); return(1);}
// If input
if (strcmp(argv[1],"-i") == 0) {
char *pattern = argv[2];
search_and_print(pattern, stdin);
}
// If file
if (strcmp(argv[1],"-f") == 0) {
char *pattern = argv[3];
// Check if file exists
// Open file
FILE *file = fopen( argv[2], "r" );
search_and_print(pattern, file);
fclose( file );
}
}
void search_and_print ( char pattern[], FILE* search_file ) {
// Read through file
const int MAX_CHARACTERS_PER_LINE = 1000;
char* line[MAX_CHARACTERS_PER_LINE];
while ( fgets(*line, MAX_CHARACTERS_PER_LINE, search_file) != NULL )
if ( strstr(*line, pattern) != NULL )
printf(*line);
}
You have quite a few bugs here.
char* line[MAX_CHARACTERS_PER_LINE];
defines an array of 1000 pointers, not characters. fgets(*line, ... passes the first of those pointers, which is uninitialized, to fgets, most likely causing a segvio.
printf(*line);
The first argument to printf is a format. Never ever pass user input as the format, as this opens a huge security hole in your program ... see http://en.wikipedia.org/wiki/Uncontrolled_format_string
You should use fputs(line) or printf("%s", line) (once you fix the declaration of line).
int main
You don't return a value (except in the error case) ... that results undefined behavior.
FILE *file = fopen( argv[2], "r" );
You should check whether this succeeds. If the file can't be opened (e.g., it doesn't exist), passing it to fgets results in undefined behavior.
if (argc < 2) { printf(NOT_ENOUGH_VARIABLES); return(1);}
This test isn't sufficient for your -f case.
you don't need
char* line[MAX_CHARACTERS_PER_LINE];
this is a pointer to arrays (maybe useful if you want to store the file or input line by line) and you haven't allocated it first. so the seg fault is quite obvious.
change your search_and_print to this:
void search_and_print ( char pattern[], FILE* search_file ) {
// Read through file
const int MAX_CHARACTERS_PER_LINE = 1000;
char line[MAX_CHARACTERS_PER_LINE];
while ( fgets(line, MAX_CHARACTERS_PER_LINE, search_file) != NULL )
if ( strstr(line, pattern) != NULL )
printf("%s\n", line);
}
additional to Jim Balter's very good advices, also I would suggest using getopt for parsing your parameters.
For future reference for anyone, here is the code with the suggested changes that seems to work. Thanks again for the help!
#include <stdio.h>
#include <string.h>
void search_and_print ( char pattern[], FILE* search_file );
int usage(const char* err);
const char USAGE[] =
"\nUSAGE: a.out [-i] [-f filename] (Search Pattern)";
int main ( int argc, char *argv[] ) {
const char TOO_MANY_VARIABLES[] = "Too many arguments from the command line!";
if (argc < 2) return usage("Not enough options");
if (argc > 4) return usage("Too many arguments from the command line!");
// If input
if (strcmp(argv[1],"-i") == 0) {
if (argc > 2) {
char *pattern = argv[2];
search_and_print(pattern, stdin);
}
else {
printf("Need a pattern to search by!");
return 1;
}
}
// If file
if (strcmp(argv[1],"-f") == 0) {
if (argc > 3) {
char *pattern = argv[3];
// Open file
FILE *file = fopen( argv[2], "r" );
// Check if file exists
if ( file != NULL) {
search_and_print(pattern, file);
fclose( file );
} else {
printf("File not found!");
return 1;
}
} else {
printf("Need a pattern to search by!");
return 1;
}
}
return 0;
}
int usage(const char* err) {
fprintf(stderr, "%s\n%s\n", err, USAGE);
return 1;
}
void search_and_print ( char pattern[], FILE* search_file ) {
const int MAX_CHARACTERS_PER_LINE = 1000;
char line[MAX_CHARACTERS_PER_LINE];
// Read through file
while ( fgets(line, MAX_CHARACTERS_PER_LINE, search_file) != NULL )
if ( strstr(line, pattern) != NULL )
printf("%s", line);
}