Segmentation fault in getc - c

Its just a program where i am trying to read the number of occurrences of the word passed as an argument in the file which is also passed as next argument.
Code looks like below :
#include <stdio.h>
extern void exit(int);
void main(int argc, char *argv[]) {
char C, buf[10];
int count = 0, i = 0;
FILE *fp;
if ( argc != 3 ) {
printf("Please provide proper args\n");
exit(0);
}
fp = fopen(argv[2], "r");
if( fp == NULL ) {
printf("File couldn't be opened\n");
exit(1);
}
else {
do {
while ( (C = fgetc(fp)) && ( C != ' ') ) {
//if ( C == EOF ) break;
buf[i] = C;
i++;
}
buf[i] = '\0';
i = 0;
if (strcmp(argv[1], buf) == 0) count++;
} while (C != EOF );
}
close(fp);
printf("Total \"%s\" occurances is %d\n", argv[1], count);
}
GDB :
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a925fd in getc () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.18-12.fc20.x86_64
Now it will not segfault if i remove the comment before the "if" statement after the first while. The only line in this program is commented.
But if that is the case then we have definitely crossed the getc part and entered into the while. I was thinking that the problem could be while doing the strcmp. But why do i see the error in getc in gdb.

With the check for end of file outcommented you actually have an infinite loop, where fgetc continues to return EOF but you never check for it. This leads to undefined behavior because you will then write well beyond the bounds of the buf array. What probably happens is that you then overwrite the FILE pointer fp, casing the next call to fgetc to operate on an invalid FILE pointer.
Also as noted in another comment, fgets returns an int. You need to know that (char) EOF != (int) EOF.

Related

Reading only letters in C using fscanf

Is it possible to use fscanf to read words without symbols from a text file
this function prints one word on a single line but if the word had comma or brackets it will print those too is there anyway to only print letters?
void load(const char *file)
{
FILE *inFile = fopen(file , "r");
if (inFile == NULL )
{
return false;
}
char word[LENGTH];
while (fscanf(inFile, "%s", word) != EOF)
{
printf("%s\n", word);
}
}
Your function will not compile at all as it is returning value and it is declared as void
Read char by char and print only what you want.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
bool load(const char *file)
{
FILE *inFile = fopen(file , "r");
if (inFile == NULL )
{
return false;
}
char word;
int retval;
while ((retval = fscanf(inFile, "%c", &word)) != EOF && retval == 1)
{
if(isalnum((unsigned char)word) || isspace((unsigned char)word))
printf("%c", word);
}
fclose(inFile);
return true;
}
Is it possible to use fscanf to read words without symbols from a text file
Well, yes...
You can use a scanset to tell which characters to match. Like:
%[a-zA-Z]
This will match/accept all upper and lower case letters and reject all other characters.
But... That will give you another problem. When the next character the the file doesn't match, the file pointer won't be advanced and you are kind of stuck. To handle that you need a way to skip non-matching characters, e.g. fgetc to read a single character.
Something like:
char word[32];
while (1)
{
int res = fscanf(inFile, "%31[a-zA-Z]", word); // At most 31 characters and only letters
if (res == EOF) break;
if (res == 1)
{
printf("%s\n", word);
}
else
{
// Didn't match, skip a character
if (fgetc(inFile) == EOF) break;
}
}
With a file like:
Hallo World, having() fun ....
Oh,yes...
the output is
Hallo
World
having
fun
Oh
yes
An alternative that only uses fsanf could be:
char word[32];
while (1)
{
int res = fscanf(inFile, "%31[a-zA-Z]", word); // Read letters
if (res == EOF) break;
if (res == 1)
{
printf("%s\n", word);
}
res = fscanf(inFile, "%31[^a-zA-Z]", word); // Skip non-letters
if (res == EOF) break;
}
Notice the ^ in the second scanset. It changes the meaning of the scanset to be "Don't match ...." So the code alternate between "Read a word consisting of letters" and "Skip everything not being letters" which is likely a better way of doing this than the fgetc method above.
That said, I normally prefer reading the file using fgets and then parse the buffer afterwards (e.g. using sscanf) but that's another story.

C: Segmentation fault when signal received

I'm trying to write a program of a basic shell that exits at EOF and handles SIGINT without quitting. It was working within one functionless c file but upon creating functions I ran into an error where EOF and SIGNINT would cause seg faults. I'm unsure what's causing this and hoping that someone will spot something I did not. Below is the function I think causing the issue, its the first thing done after the Shell reads a command (or where I'm applying signals).
int check_redirect(char *line, int flag)
{
int n = 0;
if (line == NULL) return (flag);
else
{
do
{
if (line[n] == '>') flag = 1;
n++;
}while (line[n] != '\n');
}
return (flag);
}
This is where the function is called:
char buffer[15];
time_t now = time(NULL);
strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now) );
fprintf(stdout, "%s # ", buffer);
signal(SIGINT, SIG_IGN);
read = getline (&line, &len, stdin);
signal(SIGINT, SIG_DFL);
flag = check_redirect(line, flag);
Hopefully this is clear enough. This is at the beginning of a loop, which is looking for input to execute as a command, having printed out the prompt (date and time #). The commands work mostly but act as if they are lost occasionally, which I think may be related to this signal processing error.
Thanks in advance.
Seg fault can occur from an infinite loop
You have the potential for an infinite loop here:
... }while (line[n] != '\n');
Suggest checking for more than just the \n character.
You could use strstr(line, "\n"); to verify newline exists before entering loop, for example.
Change your code to
int check_redirect(char *line, int flag, int len)
{
int n = 0;
if (line != NULL)
{
do
{
if (line[n] == '>')
{
flag = 1;
}
n++;
}
while ((line[n] != '\n') && (n<len))
}
return (flag);
}
call it with:
flag = check_redirect(line, flag, read);

How to fix 'Segmentation Fault(core dumped)' error when reading characters from two input files?

I am in the process of writing an encryption program but have come to a halt because of the error: 'Segmentation Fault(Core Dumped)'. The below program is suppose to print from two input files:
The first input file: should be read in and then change the upper case characters to lower case characters and lower case characters to upper case characters.
The second input file: should be read in and just print the number of times the user desired character appears in the file. In this case the user desired character I want is the letter 'a'.
Let's say for example the first input file(input.txt) contains:
Hello My Name is Joe
This should print as: hELLO mY nAME IS jOE
Let's say for example the second input file(keys.txt) contains:
A
M
This should just print the character: A
NOTE This doesn't necessarily encrypt the input file yet however, i'm trying to get familiar with using more than one input file at once. I can use all the help I can get! THANK YOU!
ALSO, when compiling, the code should look like this:
gcc myProgram.c
./a.out e input.txt keys.txt
(The above 'e' just stands for encryption.)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int args, char *argc[]){
int i,c,x,len,len2;
char str[1024];
char str2[500];
FILE *finp;
FILE *keyFile;
/* ****** CODE TO ENCRYPT STARTS HERE ****** */
if((argc[1]="e")&&((finp = fopen(argc[2],"r"))==NULL)
&&((keyFile=fopen(argc[3],"r"))==NULL)){
printf("Could Not Open file %s\n", argc[2]);
exit(1);
}//End First IF statement
/* *** START CODE TO GRAB FROM 1st INPUT FILE: input.txt *** */
/*Grab strings from first input file and change lower case to upper case and
upper to lower case*/
while(fgets(str,1024,finp)!=NULL){
len = strlen(str);
for(i>0;i<len;++i){
if(((str[i]>=64)&&(str[i]<=90))||((str[i]>=97&&(str[i]<=122))))
str[i]^=32;}}
/* *** END OF CODE FOR 1st INPUT FILE **** */
/* *** START CODE TO GRAB FROM 2nd INPUT FILE: keys.txt **** */
/*Grab character from second input file and print the character*/
while(fgets(str2,500,keyFile)!=NULL){
len2 = strlen(str2);
for(x>0;x<len2;++x){
if(str2[x]=='A'){
putchar(str2[x]);
}}
/* ***** END CODE FOR 2nd INPUT FILE*** */
}
printf("%s\n",str);
fclose(finp);
return 0;}
I think the main problem in your code is that you have not initialized i and x before using them.
Replace the line
for(i>0;i<len;++i){
with
for(i=0;i<len;++i){
// ^^^ i = 0; not i > 0;
and replace the line
for(x>0;x<len2;++x){
with
for(x=0;x<len2;++x){
// ^^^ x = 0; not x > 0;
You can clean up the code at the start of the function. The logic used in
if((argc[1]="e")&&((finp = fopen(argc[2],"r"))==NULL)
&&((keyFile=fopen(argc[3],"r"))==NULL)){
printf("Could Not Open file %s\n", argc[2]);
exit(1);
}//End First IF statement
is wrong on many accounts. Replace that with more readable code:
if ( strcmp(argv[1], "e") == 0 )
{
if ( (finp = fopen(argc[2],"r")) == NULL )
{
printf("Could Not Open file %s\n", argc[2]);
exit(1);
}
if ( (keyFile = fopen(argc[3],"r")) == NULL )
{
printf("Could Not Open file %s\n", argc[3]);
exit(1);
}
}
else
{
// Decide what you want to do when the first argument is not "e".
}
in your code
(argc[1]="e")
should be
!strcmp(argv[1], "e")
Same kind of mistake for argc[2] and argc[3].
Remember, argc is of type int (not array). argv[] is of type char *.
That said, you should always check for the argc value against n befire making use of argv[n-1].
Then, please keep in mind, the second operand of && is evaluated only if the first operand yields a TRUE value. You shoule check the logic you're using in
if((argc[1]="e")&&((finp = fopen(argc[2],"r"))==NULL)
&&((keyFile=fopen(argc[3],"r"))==NULL))
I don't think it serves the purpose you want it to serve.
Also, as pointed out by Mr. #iharob, you never seem to initialize the counter variables used in either of your for loops. This will lead to undefined behavior.
You have many many errors
The first if statement, is completely wrong
The argc[1] = "e", is wrong from many points of view, first you cant compre strings with the == operator, but you didn't use the comparison operator, it's the assignment operator and you can't assign to arrays, so it's twofold wrong.
You used the && operator to check if both files where NULL at the same time, which would be false if only one of them is, making the code that follows invoke undefined behavior, possibly causing the SEGMENTATION FAULT.
You never check if the program was invoked with the correct number of arguments, but you still access the argc array, which by the way is normally argv, argc is used for the number of parameters i.e. where you used args, but that doesn't actually matter.
Your for loops are also wrong
for (i > 0 ... )
you never initialize the i, also a little bit of knowledge of how strings work in c, would make a c programmer to write the following loop to traverse the string
for (i = 0 ; ((str[i] != '\n') && (str[i] != '\0')) ; ++i)
since fgets() will read the trailing '\n' inserted by pressing the Return/Enter key and thus flushing standard input, you need to check against str[i] == '\n' but if you are paranoid you should also check for '\0' I am paranoid and I do check although that is ineficient, I prefer to do it instead of seeing unexpected things later.
Here is a sample of your program without the mistakes, I don't know if it does what you want but it's the same program just with errors that could lead to SEGMENTATION FAULT corrected
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char *argb[])
{
int i;
char str[1024];
char str2[500];
FILE *inputFile;
FILE *keyFile;
if (argc < 3) /* insufficient number of parameters provided */
return -1;
if (argb[1][0] == 'e')
return 0;
inputFile = fopen(argb[2], "r");
if (inputFile == NULL)
{
printf("Could Not Open file %s\n", argb[2]);
return -1;
}
keyFile = fopen(argb[3], "r");
if (keyFile == NULL)
{
printf("Could Not Open file %s\n", argb[2]);
fclose(inputFile);
return -1;
}
while (fgets(str, sizeof(str), inputFile) != NULL)
{
for (i = 0 ; ((str[i] != '\n') && (str[i] != '\0')) ; ++i)
{
if (((str[i] >= 64) && (str[i] <= 90)) || ((str[i] >= 97) && (str[i]<=122)))
str[i] ^= 32;
}
}
while (fgets(str2, sizeof(str2), keyFile) != NULL)
{
for (i = 0 ; ((str2[i] != '\n') && (str2[i] != '\0')) ; ++i)
{
if (str2[i] == 'A')
putchar(str2[i]);
}
}
printf("%s\n", str);
fclose(inputFile);
return 0;
}

What is the easiest way to count the newlines in an ASCII file?

Which is the fastest way to get the lines of an ASCII file?
Normally you read files in C using fgets. You can also use scanf("%[^\n]"), but quite a few people reading the code are likely to find that confusing and foreign.
Edit: on the other hand, if you really do just want to count lines, a slightly modified version of the scanf approach can work quite nicely:
while (EOF != (scanf("%*[^\n]"), scanf("%*c")))
++lines;
The advantage of this is that with the '*' in each conversion, scanf reads and matches the input, but does nothing with the result. That means we don't have to waste memory on a large buffer to hold the content of a line that we don't care about (and still take a chance of getting a line that's even larger than that, so our count ends up wrong unless we got to even more work to figure out whether the input we read ended with a newline).
Unfortunately, we do have to break up the scanf into two pieces like this. scanf stops scanning when a conversion fails, and if the input contains a blank line (two consecutive newlines) we expect the first conversion to fail. Even if that fails, however, we want the second conversion to happen, to read the next newline and move on to the next line. Therefore, we attempt the first conversion to "eat" the content of the line, and then do the %c conversion to read the newline (the part we really care about). We continue doing both until the second call to scanf returns EOF (which will normally be at the end of the file, though it can also happen in case of something like a read error).
Edit2: Of course, there is another possibility that's (at least arguably) simpler and easier to understand:
int ch;
while (EOF != (ch=getchar()))
if (ch=='\n')
++lines;
The only part of this that some people find counterintuitive is that ch must be defined as an int, not a char for the code to work correctly.
Here's a solution based on fgetc() which will work for lines of any length and doesn't require you to allocate a buffer.
#include <stdio.h>
int main()
{
FILE *fp = stdin; /* or use fopen to open a file */
int c; /* Nb. int (not char) for the EOF */
unsigned long newline_count = 0;
/* count the newline characters */
while ( (c=fgetc(fp)) != EOF ) {
if ( c == '\n' )
newline_count++;
}
printf("%lu newline characters\n", newline_count);
return 0;
}
Maybe I'm missing something, but why not simply:
#include <stdio.h>
int main(void) {
int n = 0;
int c;
while ((c = getchar()) != EOF) {
if (c == '\n')
++n;
}
printf("%d\n", n);
}
if you want to count partial lines (i.e. [^\n]EOF):
#include <stdio.h>
int main(void) {
int n = 0;
int pc = EOF;
int c;
while ((c = getchar()) != EOF) {
if (c == '\n')
++n;
pc = c;
}
if (pc != EOF && pc != '\n')
++n;
printf("%d\n", n);
}
Common, why You compare all characters? It is very slow. In 10MB file it is ~3s.
Under solution is faster.
unsigned long count_lines_of_file(char *file_patch) {
FILE *fp = fopen(file_patch, "r");
unsigned long line_count = 0;
if(fp == NULL){
return 0;
}
while ( fgetline(fp) )
line_count++;
fclose(fp);
return line_count;
}
What about this?
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 4096
int main(int argc, char** argv)
{
int count;
int bytes;
FILE* f;
char buffer[BUFFER_SIZE + 1];
char* ptr;
if (argc != 2 || !(f = fopen(argv[1], "r")))
{
return -1;
}
count = 0;
while(!feof(f))
{
bytes = fread(buffer, sizeof(char), BUFFER_SIZE, f);
if (bytes <= 0)
{
return -1;
}
buffer[bytes] = '\0';
for (ptr = buffer; ptr; ptr = strchr(ptr, '\n'))
{
++count;
++ptr;
}
}
fclose(f);
printf("%d\n", count - 1);
return 0;
}

Understanding type casting in c

I'm following a book on c, and I come to some code that reads a file with 3 lines of text.
#include <stdio.h>
int main (int argc, const char * argv[]) {
FILE *fp;
int c;
fp = fopen( "../../My Data File", "r" );
if ( NULL == fp ) {
printf( "Error opening ../My Data File" );
} else {
while ( (c = fgetc( fp )) != EOF )
putchar ( c );
fclose( fp );
}
return 0;
}
I tried to modify it, to detect each line and print the current line number by making these modifications.
int line = 1;
while ( (c = fgetc( fp )) != EOF ){
if (c == '\n'){
printf(" LINE %d", line);
putchar( c );
line++;
}
else {
putchar ( c );
}
}
But it failed to print the line #, till I changed the type of the variable c to a char. Is there a way to check for a newline while still using c as an int?
What is the proper way to check for a newline?
Your code prints line numbers at the end of a line, right before printing the '\n', because of the way you have written the loop. Otherwise, your code should work.
If you want your code to print the line numbers at the beginning, you can do something like (untested):
int line_num_printed = 0; /* indicating if we printed a line number */
int line = 1;
while ((c = fgetc(fp)) != EOF) {
if (!line_num_printed) {
printf("LINE %d: ", line);
line_num_printed = 1;
}
putchar(c);
if (c == '\n'){
line++;
line_num_printed = 0;
}
}
If there is something else that "doesn't work", you should post complete code and tell us what doesn't work.
Edit: The proper way to check a character for a newline is to test against '\n'. If the character came from a file, you should also make sure you open the file in text mode, i.e., without a b in the second argument to fopen().
Also, you want c to be of type int, not char. This is because in C, EOF is a small negative number, and if char is unsigned, comparing it against a negative number convert the value of EOF to a positive value (equal to EOF + UCHAR_MAX + 1 most likely). Therefore, you should not change c to char type. If you do, the comparison c != EOF might be false even when fgetc() returns EOF.
Usually the integer code for a new line ('\n') is 13. So you could do ( if (c == 13) ), but also note that windows files use 2 characters to define a new line '\r' and '\n'. The integer character for '\r' is 10. But basically yes you can keep 'c' as an int and just compare against 13.

Resources