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);
}
Related
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
The programm should be able to open a file like myFile.txt,
alltough it's real name is myFile without the extension .txt.
So I wrote the function called removeFileExtension() in order
to achieve that.
It does open my file by copying the string from text into filename:
strcpy(filename,text);
FILE *fp = fopen(filename, "r");
So I tried to check what the difference between text and my processed
string from removeFileExtension is.
To check if it even works I mate a function called strComparison(),
which returns either 0 when it is qual or 1 if unequal.
The thing is, after removing the file extension, it shows that both strings
are qual, but I am still not able to open the file.
When I type in ./a.out myFile.txt my comparison function returns 0,
it is equal, but fopen() still is not able to open the file,
respectively I allways get a Segmentation fault.
Does anyone see the problem here?
Why am I getting a Segmentation fault?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void removeFileExtension(char *haystack);
int strComparison(char *one, char *two);
int main(int argc, char const *argv[])
{
//----------------------------------------------------------------------------
// CHECK INPUT VALIDITY
//
if (argc != 2)
{
printf("Usage: ./ass2 [file-name]\n");
return 1;
}
//----------------------------------------------------------------------------
// OPEN FILE (INITIAL)
//
char filename[32];
strcpy(filename, argv[1]);
FILE *fp = fopen(filename, "r"); //FOPEN
//FILE *fp = fopen("start_of_story\0txt", "r"); // this way does work
if (fp == NULL)
{
// IF NOT FOUND: REMOVE EXTENSION
removeFileExtension(filename);
char text[] = "myFile\0";
int ret_val = -1;
ret_val = strComparison(filename, text);
if (ret_val == 0)
printf("[DEBUG] equal\n");
else
printf("[DEBUG] unequal\n");
printf("[DEBUG] ret_val: %d\n", ret_val);
printf("[DEBUG] '%s'\n", filename);
FILE *fp = fopen(filename, "r"); //FOPEN
// IF STILL DOESN'T WORK: ERROR
if (fp == NULL)
{
printf("[ERR] Could not read file %s.\n", filename);
return 3;
}
}
//--------------------------------------------------------------------------
// READ DATA (INITIAL)
//
int bufsize = 1024;
char *buffer = malloc(bufsize * sizeof(char)); //MALLOC
if (!buffer)
{
printf("[ERR] Out of memory.\n");
return 2;
}
fseek(fp, 0, SEEK_SET);
fread(buffer, bufsize, 1, fp);
printf("[DEBUG] %s\n", buffer);
fclose(fp); //FCLOSE
free(buffer);
buffer = NULL;
return 0;
}
void removeFileExtension(char *haystack)
{
char needle[1] = ".";
char *retp; // return pointer
retp = strstr(haystack,needle);
if (*retp == '.')
{
while (*retp != '\0')
{
*retp++ = '\0';
}
printf("[DEBUG] %s\n", haystack);
}
}
int strComparison(char *one, char *two)
{
do
{
printf("[DEBUG] '%c' == '%c'\n", *one, *two);
if (*one++ != *two++)
{
return 1; // return 1 if unqual
}
}
while ( (*one != '\0') || (*two != '\0') );
return 0; // return 0 if qual
}
Resulting output:
user#host ~/Desktop $ ./a.out myFile.txt
[DEBUG] myFile
[DEBUG] 'm' == 'm'
[DEBUG] 'y' == 'y'
[DEBUG] 'F' == 'F'
[DEBUG] 'i' == 'i'
[DEBUG] 'l' == 'l'
[DEBUG] 'e' == 'e'
[DEBUG] equal
[DEBUG] ret_val: 0
[DEBUG] 'myFile'
[ERR] Could not read file myFile.
user#host ~/Desktop $
Quoting C11, chapter 7.24.5.7
char *strstr(const char *s1, const char *s2);
The strstr function locates the first occurrence in the string pointed to by s1 of the
sequence of characters (excluding the terminating null character) in the string pointed to
by s2.
So, both the arguments passed to strstr has to be strings. In your case,
char needle[1] = ".";
is not a string. You did not allow the space for the null-terminator. Either use
char needle[2] = ".";, at least, or,
char needle[ ] = ".";, or,
char const* needle = ".";
As a side effect, whenever the call to removeFileExtension() is reached, you'll face with undefined behavior
That said, beware!!
You are doing something like
retp = strstr(haystack,needle);
if (*retp == '.')
i.e., dereferencing the returned pointer from strstr(). If, strstr() returns a NULL pointer, you'll again be trapped in UB.
EDIT:
For those who still has confusion about string, check definition in chapter ยง7.1.1 (emphasis mine)
A string is a contiguous sequence of characters terminated by and including the first null
character. [...]
At least I found the problem:
After removing the file's extension, I am still
trying to open the old file pointer fp, which
gave me the NULL-pointer back. The new file pointer
inside the body of the if(fp == NULL){...} only
exists inside the scope of the if-statement.
So I created a test_pointer, which first looks if
the file even exists, if not, he removes the extension.
Than I try again to open the file, this time with fp.
Thanks to everybody for the hints, especially to
Sourav Ghosh
for your improvement suggestions!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int removeFileExtension(char *haystack);
int main(int argc, char const *argv[])
{
char filename[64];
strcpy(filename, argv[1]);
//----------------------------------------------------------------------------
// CHECK INPUT VALIDITY
//
if (argc != 2)
{
printf("Usage: ./ass2 [file-name]\n");
return 1;
}
//----------------------------------------------------------------------------
// CHECK FILE EXISTENSE
//
FILE *test_pointer = fopen(filename, "r"); //FOPEN
if (test_pointer == NULL) // if not found: remove extension
{
int ret_val = removeFileExtension(filename);
if (ret_val == -1)
{
printf("[ERR] Could not remove file extension.\n");
return 3;
}
}
//----------------------------------------------------------------------------
// OPEN FILE (INITIAL)
//
FILE *fp = fopen(filename, "r"); //FOPEN
if (fp == NULL) // if still doesn't work: error
{
printf("[ERR] Could not read file %s.\n", filename);
return 3;
}
//----------------------------------------------------------------------------
// READ DATA (INITIAL)
//
int bufsize = 1024;
char *buffer = malloc(bufsize * sizeof(char)); //MALLOC
if (!buffer)
{
printf("[ERR] Out of memory.\n");
return 2;
}
fseek(fp, 0, SEEK_SET);
fread(buffer, bufsize, 1, fp);
fclose(fp); //FCLOSE
printf("[DEBUG] %s\n", buffer);
free(buffer); //FREE
buffer = NULL;
return 0;
}
int removeFileExtension(char *haystack)
{
char needle[] = ".";
char *retp; // return pointer
retp = strstr(haystack,needle);
if(!retp) // to prevent UB
return -1;
if (*retp == '.')
{
while (*retp != '\0')
{
*retp++ = '\0';
}
printf("[DEBUG] %s\n", haystack);
}
return 0;
}
1) I'm trying to open a file, read the mix data (ints, chars and strings) and store them into args.
1.1) so in the sample.txt is a total of 13 (excluding args[0])
2) Need to read a file from terminal "./myprog.c < sample.txt"
Heres my code and have no idea where i went wrong:
sample.txt:
123 213 110 90 1
hello my friend
boo bleh
a b c
myprog.c:
#include <stdio.h>
int main()
{
int i = 1;
FILE *fstin=fopen(argv[0], "r"); //open the file
if (fstin == NULL) {
puts("Couldn't fopen...");
return -1;
}
//Getting all the inputs from file
while ((fscanf(fstin, "%d", argv[i])) != EOF){
i++;
}
fclose(fstin);
for (i=0; i<10; i++) {
printf("%d\n",argv[i]);
}
return 0;
}
Any help is greatly appreciated!
PS: Would like if anyone could post their complete solution? Will upload unto this post and let everyone have a review of this problem
PPS: Please excuse the poor level of coding as I am a beginner and completely new to C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int ac, char *av[]){
int i, argc=0;
char **argv=NULL, data[16];
FILE *fstin = stdin;
if(ac == 2){
if(NULL==(fstin = fopen(av[1], "r"))){
puts("Couldn't fopen...");
return -1;
}
}
while (1==fscanf(fstin, "%15s", data)){
argv = realloc(argv, (argc+1)*sizeof(char*));
argv[argc] = malloc(strlen(data)+1);
strcpy(argv[argc++], data);
}
if(ac == 2)
fclose(fstin);
for (i=0; i<argc; ++i) {
printf("%s\n", argv[i]);
}
//deallocate
return 0;
}
You are making mistake at 2nd point where you divert your file to other file which is wrong. Actually you need to first compile and need to make executable.
gcc -o my_prog ./myprog.c -Wall
You need to execute this program as below to read file from c program:
./my_prog ./sample.txt
As you are new to C programming first go to man pages related to file operations.
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
//If command line argument is not inserted then stop operation
if (2 != argc) {
printf("Invalid number of arguments : %d\n", argc);
return -1;
}
int size = 0, ret = 0;
char *data = NULL;
FILE *fp = NULL;
//Open file in read mode given from command line argument
if (NULL != (fp = fopen(argv[1], "r")))
{
//Find size of file
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
//if file is empty no need to read it.
if (size > 0)
{
//Data pointer which contains file information
data = (char *) calloc(sizeof(char), size);
if (NULL != data)
{
//Read whole file in one statement
fread(data, sizeof(char), size, fp);
printf("File %s is readed successfully\n", argv[1]);
printf("Data:\n");
printf("%s\n", data);
free(data); data = NULL;
}
else
{
perror("memory allocation failed\n");
ret = -1;
}
}
else
{
printf("File %s is empty\n", argv[1]);
}
fclose(fp); fp = NULL;
}
else
{
perror("File open failed\n");
ret = -1;
}
return ret;
}
Now Test it on your setup and if any query please post comments.
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);
}
I have problem with getNumber function, because my output_file contains zeros. And in my opinion it should not. I want my program to print all numbers and then add them up.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CHUNK 12
char *getNumber(FILE *infile);
int main(int argc, char *argv[])
{
char *number, *pEnd;
FILE *infile, *outfile;
int newNumber, sum = 0;
if(argc != 3)
{
printf("Missing argument!\n");
exit(1);
}
infile = fopen(argv[1], "r");
if(infile != NULL)
{
outfile = fopen(argv[2], "w");
if(outfile == NULL)
{
printf("Error, cannot open the outfile!\n");
abort();
}
else
{
while(!feof(infile))
{
number = getNumber(infile);
if(number == NULL)
{
free(number);
abort();
}
newNumber = strtol(number, &pEnd, 10);
sum += newNumber;
if(!*pEnd)
printf("Converted successfully!\n");
else printf("Conversion error, non-convertible part: %s", pEnd);
fprintf(outfile, "%d\n", newNumber);
free(number);
}
fprintf(outfile, "\nSum: %d\n", sum);
}
}
else
{
printf("Error, cannot open the infile!\n");
abort();
}
fclose(infile);
fclose(outfile);
return 0;
}
char *getNumber(FILE *infile)
{
char *number, *number2;
int length, cursor = 0, c;dwwd
number = (char*)malloc(sizeof(char)*CHUNK);
if(number == NULL)
{
printf("Error!\n");
return NULL;
}
length = CHUNK;
while(!isspace(c = getc(infile)) && !feof(infile))
{
if(isdigit(c))
{
number[cursor] = c;
cursor++;
if(cursor >= length)
{
length += CHUNK;
number2 = (char*)realloc(number, cursor);
if(number2 == NULL)
{
free(number);
return NULL;
}
else number = number2;
}
}
}
number[cursor] = '\0';
return number;
}
I would be really grateful for any help.
I am also sending two files, input_file and output_file:
Your condition here:
while(!isspace(c = getc(infile)) && !feof(infile))
Breaks every time you encounter space. After that you will always print the number. That means that for every interval(also for the end of the file) that is not preceded directly with digit you will print one extra zero in the output file.
Maybe add one flag whether you entered the while at least once. If you have not - just do not print anything.
You have to add else statement to your if(isdigit(c)) to break the loop when a non digit character is found after having found a digit previously.
if(isdigit(c))
{
// your existing code
}
else if (cursor != 0)
{
break;
}
Hope this helps.
EDIT:
Just replace
fprintf(outfile, "%d\n", newNumber);
with
if(0 != newNumber) fprintf(outfile, "%d\n", newNumber);
From the strtol c library manpage:
If there were no digits at all, strtol() stores
the original value of nptr in *endptr (and returns 0)
You always assign to newNumber and don't check for the case where strtol doesn't actually return a converted number but a instead returns a 0 because it couldn't find a number. That's why you have all the zeroes in your output file.