ploosh
ploosh

Reputation: 1

File I/O in C Segmentation Fault

I know what a segmentation fault is, i don't need to know its definition :) I just need to know where it's coming from in my code. This program is meant to get words as input, read from a text file, write to a separate text file and then print all the words from the read file and the input.

#include<stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char*argv[]){
    FILE *read;
    FILE *write;
    char **list=malloc(sizeof(char*));
    char **oldlist=malloc(sizeof(char*));
    char *oldword=malloc(sizeof(char));
    char exit[]="end";
    int a, c, r=0, w=0, n=0, z= 0, y=0, d=0, g=0;

//check arg
for(a=0; a<argc; a++){
    if(strcmp(argv[a], "-r")==0){
        r =1;
        read=fopen("read.txt", "r");
    }
    else if(strcmp(argv[a], "-w")==0){
        w =1;
        write=fopen("write.txt", "w");
    }   
}
if(r==0 && w==0){
    printf("Error: Invalid Command.\n");
}
printf("Read = %d | Write = %d\n", r, w);

//getwords
printf("Enter your words: ");
while(1){
char *word=malloc(sizeof(char));
list=realloc(list, sizeof(char*)*(z+10));
word=realloc(word, sizeof(char)*(z+10));
scanf("%s", word);
              if (strcmp(word,exit)==0){
        break;
              }
              else{
                *(list+z) = word;
            z++;
          }
}   

//read
if (r==1){
    do{
        while(1){
            *(oldword+d)=fgetc(read);
            d++;
        }
    }while(feof(read) != 0);            
}
*(oldword+(d-1))="\0";

printf("Your words are:\n");
            puts(oldword);
    for(c=0; c<n; c++){
            puts(*(list+c));
    }

    //write
    if (w ==1){
        if(w==1){
            fputs(*(oldlist+c),write);
        }
    for(c=0; c<n; c++){
            fputs(*(list+c),write); 
        }
    }
    //end
    free(list);
    fclose(read);
    fclose(write);          
    return 0;

}

Upvotes: 0

Views: 820

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 753705

You allocate 1 byte for the word:

char *word=malloc(sizeof(char));

You then read a string into it. This is a buffer overflow, and leads to great unhappiness (and questions like this on Stack Overflow). Specifically, reading long words will trample over control information in the 'heap' (the data space controlled by malloc() et al) and scramble data that is used to determine which space is available for use and which is not. What constitutes a 'long word' depends on the system; technically, any string except the empty string (just a terminal '\0') is too long, but you might get away with blue murder if the words are 7 bytes or less.


But shouldn't the realloc take care of the memory problem? I'm trying to make the string input unlimited.

Hmmm...it's a little odd as a way of doing business, but the realloc() of word before you actually use it gets you around some of the problem.

Specifically, you can read up to and including 9 characters before you overflow the memory allocation of word on the first time around the loop. However, that is a long way from making it 'unlimited', and making it unlimited is non-trivial. One issue is that %s stops scanning at a white space characters; that works in your favour, on the whole. Another is that you seem to be using z as a count of the number of strings you've entered and also as a length for the strings you can enter. You are not reallocating list if the list grows beyond 10 entries.

You can still run into various problems. Your handling of oldword doesn't do the extra realloc(), for example; it just allocates one byte. Then you have an infinite loop that is completely unbounded (if it is entered at all). This loop is a disaster:

    while(1){
        *(oldword+d)=fgetc(read);
        d++;
    }

Upvotes: 3

rpamely
rpamely

Reputation: 148

If you compile with debugging on (the g flag) and run under valgrind it should give you a pretty good indication of why it seg faults.

Upvotes: 2

Related Questions