Segmentation fault when passing pointer to function - c

I am getting a segmentation fault when I call my getField(char *line, int field) function in my while loop and I'm not sure why. I'm trying to pass a line to the function and a column number so that I can grab specific columns from each line in a csv file and print them to the screen. Thanks for input.
void getField(char *line, int field);
int main(int argc, char *argv[]) {
if(argc < 3) {
fprintf(stderr, "Too few arguments \"%s\".\n", argv[0]);
}
if(atoi(argv[1]) < 1) {
fprintf(stderr, "First argument must be >= 1 \"%s\".\n", argv[1]);
}
FILE *fp = fopen(argv[2], "r");
if(fp == NULL)
fprintf(stderr, "Cannot open file %s\n", argv[0]);
char buf[80];
while(fgets(buf, 80, fp) != NULL) {
getField(buf, atoi(argv[1]); // seg fault is happening here
}
return 0;
}
void getField(char *line, int field) {
printf("here2");
//char *ln = line;
int column = field - 1;
int idx = 0;
while(column) {
//printf("here");
if(line[idx] == ',') field--;
idx++;
}
for(int j = idx; ; ++j) {
if(line[j] == ',') break;
printf("%s", line[j]);
}
printf("\n");
printf("%d", idx);
}

One obvious error is that you have an infinite loop here, and you will eventually access illegal memory.
while(column) {
//printf("here");
if(line[idx] == ',') field--;
idx++;
}
You are not modifying column at all, so your loop cannot possibly end.
column will not update itself when you update field, so you will have to update it if you want it to update.
while(column) {
//printf("here");
if(line[idx] == ',') field--;
idx++;
column = field - 1;
}
Note on debugging segfaults using printf.
The function printf prints to stdout and stdout likes to buffer output. This means that sometimes if you try to find a segfault by moving a print statement down your code until it fails to print, you will misunderstand where the segfault it happening. In particular, a printf line that appears before the line that actually contains the segfault may not print even if you might expect it to.
If you want to use this strategy (instead of gdb), you can force it to print by using fflush(stdout); immediately after your debugging printf.

while(column) {
//printf("here");
if(line[idx] == ',') column--; // Changed field-- to column--
idx++;
}

In following line:
printf("%s", line[j]);
you are using the %s format specifier but you are passing a char as argument.
You probably want this (%c format specifier fot printing a char):
printf("%c", line[j]);

You are accessing out of bounds of the array in the function getField because the while loop never exits. This invokes undefined behaviour and most likely program crash due to segfault which is what is happening in your case. I suggest the following changes to your program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void getField(char *line, int field);
int main(int argc, char *argv[]) {
if(argc < 3) {
fprintf(stderr, "Too few arguments \"%s\".\n", argv[0]);
return 1; // end the program
}
if(atoi(argv[1]) < 1) {
fprintf(stderr, "First argument must be >= 1 \"%s\".\n", argv[1]);
return 1; // end the program
}
FILE *fp = fopen(argv[2], "r");
if(fp == NULL) {
fprintf(stderr, "Cannot open file %s\n", argv[0]);
return 1; // end the program
}
char buf[80];
while(fgets(buf, 80, fp) != NULL) {
getField(buf, atoi(argv[1])); // seg fault is happening here
}
return 0;
}
void getField(char *line, int field) {
int len = strlen(line);
char temp[len + 1];
strcpy(temp, line);
int count = 0;
char ch = ',';
char *p = temp;
char *q = NULL;
while(count < field - 1) {
q = strchr(p, ch);
if(q == NULL) {
printf("error in the value of field\n");
return;
}
count++;
p = q + 1;
}
q = strchr(p, ch);
if(q != NULL)
*q = '\0';
else
temp[len-1] = '\0';
printf("%s\n", p);
}

Related

Warnings and segmentation fault core dumped

This is a program to remove particular lines in a file. It copies the lines which are needed and prints it in another file in the same directory. I'm not getting any errors except for warnings such as incompatible pointer type [-Wincompatible-pointer-types]. When I run the code I also get the prtintf statement but when entered input Segmentation fault (core dumped). Is it related to the warnings or is it something else ?
code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include <ctype.h>
char *name_find(char *buf[], char *name[]) {
const char *p = NULL;
size_t len = strlen(name);
if (len > 0) {
for (p = buf ; (p = strstr(p, name)) != NULL; p++) {
if (p == buf || !isalnum((unsigned char)p[-1])) {
if (!isalnum((unsigned char)p[len]))
break; /* we have a match! */
p += len; /* next match is at least len+1 bytes away */
}
}
}
return p;
}
int main()
{
char name[25];
char buf[100];
setenv("PFILE","/home/ashwin/Desktop/FILE/",1);
char ori_path[100],new_path[100];
if (!getenv("PFILE")){
}
else{
strcpy(ori_path, getenv("PFILE"));
strcpy(new_path, getenv("PFILE"));
strcat(ori_path, "shadow");
strcat(new_path, "shadow1");
}
bool success=false;
printf("Enter the command\n ");
printf("userdel ");
FILE *fold = fopen(ori_path, "r"); // old file
FILE *fnew = fopen(new_path, "w"); // new temp file
fgets(name,25,stdin);
for(int i = 0; i < strlen(name); i++)
{
if(name[i] == '\n')
{
name[i] = '\0';
break;
}
}
while (fgets(buf, 100, fold)) {
// read lines until error or EOF
if (!name_find(buf, name)) {
fprintf(fnew, "%s", buf);
success=true;
}
}
if(success){
printf("Success !!!\n");
}
return 0;
}
char *name_find(char *buf[], char *name[])
You use char *buf[], which means buf is an array of pointers to char, not a pointer to char. Use char* buf instead. Same goes for name.
Additionally:
FILE *fold = fopen(ori_path, "r"); // old file
FILE *fnew = fopen(new_path, "w"); // new temp file
You should check if the opening of the streams to the files were successful by checking the returned pointers for a null pointer:
FILE *fold = fopen(ori_path, "r"); // old file
if(!fold)
{
fputs("Error at opening fold!", stderr);
exit(1);
}
FILE *fnew = fopen(new_path, "w"); // new temp file
if(!fnew)
{
fputs("Error at opening fnew!", stderr);
exit(1);
}
Try this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
char *name_find(char *buf, char *name) {
const char *p = NULL;
size_t len = strlen(name);
if (len > 0) {
for (p = buf ; (p = strstr(p, name)) != NULL; p++) {
if (p == buf || !isalnum((unsigned char)p[-1])) {
if (!isalnum((unsigned char)p[len]))
break; /* we have a match! */
p += len; /* next match is at least len+1 bytes away */
}
}
}
return p;
}
int main (void)
{
char name[25];
char buf[100];
setenv("PFILE","/home/ashwin/Desktop/FILE/",1);
char ori_path[100],new_path[100];
if (!getenv("PFILE")){
}
else{
strcpy(ori_path, getenv("PFILE"));
strcpy(new_path, getenv("PFILE"));
strcat(ori_path, "shadow");
strcat(new_path, "shadow1");
}
bool success=false;
printf("Enter the command\n ");
printf("userdel ");
FILE *fold = fopen(ori_path, "r"); // old file
if(!fold)
{
fputs("Error at opening fold!", stderr);
exit(1);
}
FILE *fnew = fopen(new_path, "w"); // new temp file
if(!fnew)
{
fputs("Error at opening fnew!", stderr);
exit(1);
}
fgets(name,25,stdin);
for(unsigned int i = 0; i < strlen(name); i++)
{
if(name[i] == '\n')
{
name[i] = '\0';
break;
}
}
while (fgets(buf, 100, fold)) {
// read lines until error or EOF
if (!name_find(buf, name)) {
fprintf(fnew, "%s", buf);
success=true;
}
}
if(success){
printf("Success !!!\n");
}
return 0;
}

Find number of occurrences for the substring in a string using C programming

I am trying a program in c to read a text file that contains array of characters or a string and find the number of occurrences of the substring called "GLROX" and say sequence found when it is found. And the "inputGLORX.txt" contains following string inside it.
GLAAAROBBBBBBXGLROXGLROXGLROXGLROXGLCCCCCCCCCCCCCCROXGGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROX
But i am getting wierd results. It would be great if some expert in C-programming helps me to solve this and thanks in advance.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define NUMBER_OF_STRINGS 40
#define MAX_STRING_SIZE 7
void seqFound()
{
printf("Sequence Found\n");
}
int main()
{
FILE *fp;
char buff[1000];
char strptrArr[NUMBER_OF_STRINGS] [MAX_STRING_SIZE];
const char *search = "GLROX";
fp = fopen("D:/CandC++/inputGLORX.txt", "r");
if(fp==NULL)
printf("It is a null pointer");
while(!feof(fp))
{
//fscanf(fp, "%s", buff);
fgets(buff, 1000,fp);
}
int len = strlen(buff);
printf("length is %d\n",len);
int count = 0;
char *store;
while(store = strstr(buff, search))
{
printf("substring is %s \n",store);
count++;
search++;
}
printf("count is %d\n",count);
while (count!=0) {
seqFound();
count--;
}
return 0;
}
As said in the comment, their are at least 2 problems in the code: your fgets will only fetch the last line (if it fetch one at all ? In any case, this is not what you want), and you are incrementing the search string instead of the buff string.
Something like this should fix most of your problems, as long as no lines in your file are longer than 999 characters. This will not work properly if you use the \n or NULL characters in your search string.
int count = 0;
while (fgets(buff, 1000, fp) != NULL)
{
char *temp = buff;
while ((temp = strstr(temp, search)))
{
printf("%d. %s\n", count + 1, temp);
count++;
temp++;
}
}
Here is a main for testing. I used argv to provide the input.txt and the search string.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *fp;
char buff[1000];
char *search;
if (argc < 3)
return (-1);
search = argv[2];
if (search[0] == '\0')
return (-1);
if ((fp = fopen(argv[1], "r")) == NULL)
return (-1);
int count = 0;
while (fgets(buff, 1000, fp) != NULL)
{
char *temp = buff;
while ((temp = strstr(temp, search)))
{
printf("%d. %s\n", count + 1, temp);
count++;
temp++;
}
}
printf("Match found: %d\n", count);
return 0;
}
The way you search in buff is wrong, i.e. this code:
while(store = strstr(buff, search))
{
printf("substring is %s \n",store);
count++;
search++; // <------- ups
}
When you have a hit, you change search, i.e. the string you are looking for. That's not what you want. The search string (aka the needle) shall be the same all the time. Instead you want to move forward in the buffer buff so that you can search in the remainder of the buffer.
That could be something like:
int main()
{
const char* buff = "GLAAAROBBBBBBXGLROXGLROXGLROXGLROXGLCCCCCCCCCCCCCCROXGGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROXGLROX";
const char* search = "GLROX";
const char* remBuff = buff; // Pointer to the remainder of buff
// Initialized to be the whole buffer
const char* hit;
int cnt = 0;
while((hit = strstr(remBuff, search))) // Search in the remainder of buff
{
++cnt;
remBuff = hit + 1; // Update the remainder pointer so it points just 1 char
// after the current hit
}
printf("Found substring %d times\n", cnt);
return 0;
}
Output:
Found substring 15 times

Why does this code keep giving me a Segfault Error when i run it in Linux?

So I'm trying to create a function that takes in a text file, which contains a bunch of words separated by the newline character, and reads the text file into a char** array.
When I run this code in netbeans on windows, it works fine but if I run it in Linux, I get a segmentation fault error.
// globals
FILE *words_file;
char **dic;
int num_words = 0;
void read_to_array() {
words_file = fopen("words.txt", "r");
char *line = NULL;
int i = 0;
size_t len = 0;
dic = (char **)malloc(99999 * sizeof(char *));
// read dic to array
while (getline(&line, &len, words_file) != -1) {
dic[i] = (char*)malloc(len);
strcpy(dic[i], line);
// get rid of \n after word
if (dic[i][strlen(dic[i]) - 1] == '\n') {
dic[i][strlen(dic[i]) - 1] = '\0';
}
++i;
num_words++;
}
//printf("%s", dic[i][strlen(dic[i]) - 1]); //testing
fclose(words_file);
dic[i] = NULL;
}
What am I missing here?
There are some problems in your program that may cause the undefined behavior that you observe:
You do not test if the file was open successfully, causing undefined behavior if the file is not where you expect it or has a different name.
You do not limit the number of lines read into the array, causing undefined behavior if the file contains more than 99998 lines, which may be be the case in linux as /usr/share/dict/words has 139716 lines on my system, for example.
Your memory allocation scheme is suboptimal but correct: you should compute the length of the word and strip the newline before allocating the copy. As coded, you allocate too much memory. Yet you should free line before returning from read_to_array and you should avoid using global variables.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **read_to_array(const char *filename, int *countp) {
FILE *words_file;
char *line = NULL;
size_t line_size = 0;
char **dic = NULL;
int dic_size = 0;
int i = 0;
words_file = fopen(filename, "r");
if (words_file == NULL) {
fprintf(stderr, "cannot open dictionary file %s\n", filename);
return NULL;
}
dic_size = 99999;
dic = malloc(dic_size * sizeof(char *));
if (dic == NULL) {
fprintf(stderr, "cannot allocate dictionary array\n");
fclose(words_file);
return NULL;
}
// read dic to array
while (getline(&line, &line_size, words_file) != -1) {
size_t len = strlen(line);
/* strip the newline if any */
if (len > 0 && line[len - 1] == '\n') {
line[--len] = '\0';
}
if (i >= dic_size - 1) {
/* too many lines: should reallocate the dictionary */
fprintf(stderr, "too many lines\n");
break;
}
dic[i] = malloc(len + 1);
if (dic[i] == NULL) {
/* out of memory: report the error */
fprintf(stderr, "cannot allocate memory for line %d\n", i);
break;
}
strcpy(dic[i], line);
i++;
}
dic[i] = NULL;
*countp = i;
fclose(words_file);
free(line);
return dic;
}
int main(int argc, char **argv) {
const char *filename = (argc > 1) ? argv[1] : "words.txt";
int num_words;
char **dic = read_to_array(filename, &num_words);
if (dic != NULL) {
printf("dictionary loaded: %d lines\n", num_words);
while (num_words > 0)
free(dic[--num_words]);
free(dic);
}
return 0;
}
Output:
chqrlie> readdic /usr/share/dict/words
too many lines
dictionary loaded: 99998 lines

C Program Segmentation Fault main()

I am novice to C programming and I have written a code to a requirement specification but I am consistently getting Segmentation Fault and unable to proceed ahead.
If the file name is 'code.c' and it runs with an error of not passing the argument (filename). But if the filename is passed, we land in Segmentation Fault.
Any help/suggestions will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
struct _data
{
char *firstName;
char *lastName;
long number;
};
// SCAN FILE
int SCAN(FILE *(*stream))
{
*stream = fopen("inputFile.data", "r");
int ch = 0, lines = 0;
while (!feof(*stream))
{
ch = fgetc(*stream);
if (ch == '\n')
{
lines++;
}
}
return lines;
}
// LOAD FILE
struct _data *LOAD(FILE *stream, int size)
{
int i;
size_t chrCount;
char *text, *number, *firstName, *lastName;
struct _data *BlackBox;
if ((BlackBox = (struct _data*)calloc(size, sizeof(struct _data))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
rewind(stream);
for (i = 0; i < size; i++)
{
getline(&text, &chrCount, stream);
firstName = strtok(text, " ");
lastName = strtok(text, " ");
number = strtok(NULL, "\n");
// Allocate memory for name part of struct.
if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName), sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName), sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
strcpy(BlackBox[i].firstName, firstName);
strcpy(BlackBox[i].lastName, lastName);
BlackBox[i].number = atol(number);
}
fclose(stream);
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char *name, int size, int inputs)
{
int i;
int found = 0;
char *search = " ";
char *firstName;
char *lastName;
if (inputs == 2)
{
firstName = strtok(name, search);
lastName = strtok(NULL, search);
}
printf("*******************************************\n");
if (inputs == 2)
{
for (i = 0; i < size; i++)
{
if (!strcasecmp(firstName, BlackBox[i].firstName) && !strcasecmp(firstName, BlackBox[i].firstName))
{
printf("The name was found at the %d entry.\n", i);
found = 1;
break;
}
}
}
else
{
for (i = 0; i < size; i++)
{
if (!strcasecmp(firstName, BlackBox[i].firstName) || !strcasecmp(firstName, BlackBox[i].firstName))
{
printf("The name was found at the %d entry.\n", i);
found = 1;
break;
}
}
}
if (found == 0)
{
printf("The name was NOT found.\n");
}
printf("*******************************************\n");
}
// FREE MEMORY
void FREE(struct _data *BlackBox, int size)
{
int i;
for (i = 0; i < size; i++)
{
free(BlackBox[i].firstName);
free(BlackBox[i].lastName);
}
free(BlackBox);
BlackBox = NULL;
}
// MAIN
int main(int argv, char **argc)
{
int size;
FILE *stream;
struct _data *BlackBox;
// argv == 1 WORKS, Below message is printed.
if (argv == 1)
{
printf("*******************************************\n");
printf("* You must include a name to search for. *\n");
printf("*******************************************\n");
}
// argv == 2 DOES NOT WORK, Segmentation Fault.
if (argv == 2)
{
size = SCAN (&stream);
BlackBox = LOAD(stream, size);
SEARCH(BlackBox, argc[1], size, 1);
}
if (argv == 3)
{
size = SCAN(&stream);
BlackBox = LOAD(stream, size);
SEARCH(BlackBox, argc[2], size, 2);
}
return 0;
}
You have a problem in this code:
firstName = strtok(text, " ");
lastName = strtok(text, " ");
number = strtok(NULL, "\n");
...
BlackBox[i].number = atol(number);
The second strtok() call should pass NULL as its first argument. As it is, the third strtok() call is certain to return NULL because the first call modifies text in such a way that the second consumes the whole thing (when tokenizing again from the beginning, as it erroneously does). You do not test for that, however, and as a result, atol() attempts to dereference a null pointer.
Update:
Additionally, as #chqrlie and later #JamesWilkins observed, you do not allocate sufficient space for BlackBox[i].firstName and BlackBox[i].lastName, as you need room for the string terminators as well. This is an entirely separate problem that could also produce a segfault. I like #chqrlie's suggestion to switch to strdup(), but it would be sufficient to just increase each allocation by one unit.
Update 2:
Furthermore, you have an issue with this line:
getline(&text, &chrCount, stream);
You do not initialize variable text before the first call, so it contains a junk value. The function allocates a buffer only when its first argument points to a NULL pointer; otherwise it writes the line to the buffer pointed to by the pointer obtained by dereferencing the first argument. Writing to a random location in memory certainly produces undefined behavior, which in practice often manifests as a segfault.
Moreover, unless you can rely on no line of the file being longer than the first, you also need to free the text pointer at the end of each loop iteration AND reset its value to NULL, so that getline() allocates a fresh buffer on the next iteration. If you do not free it on each iteration, then you need instead to free it after the end of the loop; else you will leak memory.
Try this (though I'm using Visual Studio on Windows). I added code to check for a missing '\n' on the last line, and also allowed for a variable number of search terms. I also increased the memory allocation for strings by 1 to account for the null terminating character. I noticed you are using getline(const char*..., which I think is GNU (Linux?), so I change that to fgets() just so I could compile and test it in VS (so you can change it back if you like). I put in various null checks as well, to be safer.
#include <iostream>
using namespace std;
struct _data
{
char *firstName;
char *lastName;
long number;
};
// SCAN FILE
int SCAN(FILE *(*stream))
{
*stream = fopen("inputFile.data", "r");
if (*stream == NULL)
{
perror("Error opening file");
return 0;
}
char ch = 0, lines = 0, linesize = 0;
while ((ch = fgetc(*stream)) != EOF)
{
if (ch == '\n')
{
lines++;
linesize = 0;
}
else linesize++;
}
if (linesize > 0)
lines++; // (last line doesn't have '\n')
return lines;
}
// LOAD FILE
struct _data *LOAD(FILE *stream, int lineCount)
{
int i;
size_t chrCount = 256;
char text[256], *result, *number, *firstName, *lastName;
struct _data *BlackBox;
if ((BlackBox = (struct _data*)calloc(lineCount, sizeof(struct _data))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
else memset(BlackBox, 0, sizeof(struct _data) * lineCount); // (make sure all data members are null to begin)
rewind(stream);
for (i = 0; i < lineCount; i++)
{
result = fgets(text, chrCount, stream);
if (result == NULL)
break; // (EOF)
firstName = strtok(text, " ");
lastName = strtok(NULL, " ");
number = strtok(NULL, "\n");
// Allocate memory for name part of struct.
if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName) + 1, sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName) + 1, sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
strcpy(BlackBox[i].firstName, firstName);
strcpy(BlackBox[i].lastName, lastName);
BlackBox[i].number = atol(number);
}
fclose(stream);
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char **names, int lineCount, int inputs)
{
int i, l;
int found = 0;
printf("*******************************************\n");
for (i = 0; i < inputs; ++i)
{
for (l = 0; l < lineCount; ++l)
{
if (BlackBox[l].firstName != NULL && !_stricmp(names[i], BlackBox[l].firstName)
|| BlackBox[l].lastName != NULL && !_stricmp(names[i], BlackBox[l].lastName))
{
printf("The name was found on line %d.\n", 1 + l);
found = 1;
break;
}
}
if (found) break;
}
if (!found)
printf("The name was NOT found.\n");
printf("*******************************************\n");
}
// FREE MEMORY
void FREE(struct _data *BlackBox, int lineCount)
{
int i;
for (i = 0; i < lineCount; i++)
{
if (BlackBox[i].firstName != NULL)
free(BlackBox[i].firstName);
if (BlackBox[i].lastName != NULL)
free(BlackBox[i].lastName);
}
free(BlackBox);
}
// MAIN
int main(int argc, char **argv)
{
int lineCount;
FILE *stream;
struct _data *BlackBox;
// argc == 1 WORKS, Below message is printed.
if (argc == 1)
{
printf("*******************************************\n");
printf("* You must include a name to search for. *\n");
printf("*******************************************\n");
}
// argc == 2 DOES NOT WORK, Segmentation Fault.
if (argc > 1)
{
lineCount = SCAN(&stream);
if (lineCount > 0)
{
BlackBox = LOAD(stream, lineCount);
SEARCH(BlackBox, argv + 1, lineCount, argc - 1);
FREE(BlackBox, lineCount);
}
}
return 0;
}
Tested it on the command line, and it works.
The problem is the argv and argc. argc is supposed to be an int (think argument count), while argv is meant to be char**. You have them mixed up in your main.

"aborted (core dumped)" in all programs

yesterday, during programming time everything was okay, but today I get weird error. I do not know why but after running my programs, in terminal i get this error "aborted (core dumped)", also I run programs which are already done and the problem is the same.
Example of the program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getWord(FILE *infile);
int main(int argc, char *argv[])
{
char *word;
FILE *infile, *outfile;
int n = 0;
if(argc != 2)
{
printf("Error! Type:./file_name input_file output_file\n");
abort();
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error! Cannot open the output_file\n");
abort();
}
else
{
while(!feof(infile))
{
word = getWord(infile);
if(word == NULL)
{
free(word);
abort();
}
n++;
if(n % 2 == 0)
{
fputs(word, outfile);
fputs(" ", outfile);
}
else
{
fputs(word, outfile);
fputs("(", outfile);
fputs(word, outfile);
fputs(")", outfile);
fputs(" ", outfile);
}
free(word);
}
}
}
else
{
printf("Error! Cannot open the input_file\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
char *getWord(FILE *infile)
{
char *word, *word2;
int length, cursor, c;
word = malloc(sizeof(char)*CHUNK);
if(word == NULL)
{
return NULL;
}
length = CHUNK;
cursor = 0;
while(isalpha(c = getc(infile)) && !feof(infile))
{
word[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
word2 = realloc(word, length*sizeof(char));
if(word2 == NULL)
{
free(word2);
return NULL;
}
else word2 = word;
}
}
ungetc(c, infile);
word[cursor] = '\0';
return word;
}
and the error:
Error! Type:./file_name input_file output_file
Aborted (core dumped)
The logic in your realloc is wrong.
word2 = realloc(word, length*sizeof(char));
if(word2 == NULL)
{
free(word2);
return NULL;
}
else word2 = word;
should be
word2 = realloc(word, cursor);
if(word2 == NULL)
{
free(word);
return NULL;
}
word = word2;
There are a few changes here
word starts out having length bytes allocated so there is no point in reallocating it to the same size. The variable which tracks string size is cursor so you need to reallocate to match its size.
(minor) There is no need to use sizeof(char) to help calculate the size of an allocation - this is guaranteed to be 1
If realloc fails, you need to free the original pointer, not the new one (which you know is NULL).
If the reallocation succeeds, your heap cell may have been moved, leaving word pointing to memory you don't own. The rest of the function operates on word so you need to update it to point to your new buffer (word2)
As for why this worked for you previously, the above code results in undefined behaviour in a number of places. Sometimes you're unlucky and this appears to work correctly.
If your command requires 2 parameters, you need to check for argc != 3 since the command name itself is considered an argument. If you are giving it 2 parameters, then your check on argc != 2 is failing and you're getting your error message, and the core dump due to the abort call.
Rather than abort, you should call exit with a non-zero parameter. E.g.,
if(argc != 3)
{
printf("Error! Type: %s input_file output_file\n", argv[0]);
exit(1);
}

Resources