Reputation: 43246
My program has the following requirements: If a command line argument is given, interpret it as a file name and read the input from that file. Otherwise, read input from stdin
instead. As I am going to need the input later, I want to save it into an array. And because any non-ASCII characters are to be ignored, I decided to process the input character by character. This is my code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX_WORDS 999
#define MAX_WORD_LENGTH 50
typedef struct Data{
char words[MAX_WORDS][MAX_WORD_LENGTH+1];
int numwords;
} Data;
Data* data;
int main(int argc, char** argv){
data= malloc(sizeof data);
FILE* infile;
if(argc<=1){//if no arguments, read words from stdin
infile= stdin;
}else if(argc==2){//read words from file
infile= fopen(argv[1], "r");
if(infile==NULL){
printf("failed to open word file");
return 1;
}
}
char c;
int wordindex= 0;
int charindex= 0;
while(1){//read input character by character, only accepting ASCII characters
c= fgetc(infile);
if(c=='\n' || c==EOF){
data->words[wordindex][charindex]= '\0';
wordindex++;
charindex= 0;
if(wordindex>=MAX_WORDS || c==EOF)
break;
continue;
}
if(!isascii(c))
continue;
data->words[wordindex][charindex]= toupper(c);
charindex++;
if(charindex>=MAX_WORD_LENGTH){
wordindex++;
charindex= 0;
if(wordindex>=MAX_WORDS)
break;
}
}
if(argc==2) fclose(infile);
data->numwords= wordindex-1;
//check if everything worked as intended
printf("==================\n%d word(s) read:\n", data->numwords);
for (int i = 0; i < data->numwords; i++)
printf("%d %s\n", (int)strlen(data->words[i]), data->words[i]);
}
Everything works fine if I enter the input through stdin, but if I attempt to read the input from a text file, the program segfaults. It seems to work if the text file contains only one line of text, but if there are two or more then it crashes. I'm a beginner in C and I don't see any difference between reading from stdin or a file, so I have no idea why this is happening. Can somebody enlighten me?
Upvotes: 3
Views: 59
Reputation: 70971
This
Data* data;
data= malloc(sizeof data);
allocates bytes to suite the size of data
, with data
being "just" a pointer to Data
, not Data
itself. A pointer is 4/8 bytes depending whether on a 32/64 bit platform.
Allocating to few memory here leads to writing to invalid memory soon and with this invoking the infamous Undefined Behaviour. From this moment on anything can happen ranging from crash to nothing.
If you want the number of bytes to hold Data
you want to allocate like this
data = malloc(sizeof (Data));
of even better like this
data = malloc(sizeof *data);
Also one should test the outcome of relevant system call, also malloc()
could fail:
if (NULL == data)
{
perror("malloc() failed");
exit(EXIT_FAILURE);
}
Upvotes: 2