Why do I have a segmentation fault - c

#include <stdio.h>
#include <string.h>
int main()
{
//read any text file
char const* const fName = "database-large.txt";
FILE* fp = fopen(fName, "r");
char *ptr;
char substr[5000];
long i=0, j=0;
// if file not opened
if(!fp){
printf("\n Error in open : %s ", fName);
return -1;
}
// to strore each line
char line[5000];
// read line by line
while (fgets(line, sizeof(line), fp)) {
//to extract mailid in between "From:" and "\n"
ptr = strstr(line, "Date:");
i=ptr-line;
while(line[i] !='\n')
{
substr[j] = line[i+9];
i++;
j++;
}
printf("%s\n", substr);
}
// to close the file
fclose(fp);
return 0;
}
Why does this compile but gives me a segmentation fault when when I run it because of the line "while(line[i] !='\n')".This is the only issue I have when running my code.

You need to check whether strstr returned a null pointer or not. Otherwise the following statement after the call of strstr
ptr = strstr(line, "Date:");
i=ptr-line;
can invoke undefined behavior when ptr is equal to NULL.
The second problem is that you do not reset the variable j to 0 in each iteration of the while loop.
And the third problem is that the array substr has to contain a string if you are using the conversion specifier %s in this call
printf("%s\n", substr);
Otherwise you need to write
printf("%.*s\n", ( int )j, substr);

Related

Getting strings from file gone wrong

The idea of this function is to get strings from file like this:
The file CLIENTS_BOOK: client1,client2,client3
and to get this in array of strings, eg:
CLIENTS_BOOK_ARRAY[i] to be equal to "client1"
CLIENTS_BOOK_ARRAY[i+1] to be equal to "client2"
CLIENTS_BOOK_ARRAY[i+2] to be equal to "client3"
Here is the code:
//global array
static char CLIENTS_BOOK_ARRAY[MAX_SIZE_OF_ARRAYS][MAX_SIZE_OF_ARRAYS];
void get_clients_string() {
int i = 0;
int n = 0;
char *token;
char help[256];
FILE *InputFile;
InputFile = fopen(CLIENTS_BOOK, "r");
fscanf(InputFile, "%s", help);
token = strtok(help, ",");
while (token != NULL) {
strncpy(CLIENTS_BOOK_ARRAY[i], token, MAX_SIZE_OF_ARRAYS);
token = strtok(NULL, ",");
i++;
}
n = i;
fclose(InputFile);
}
When I run it, it is giving
Segmentation fault(core dumped)
When running it with gdb it is giving
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f2ce38 in __strncpy_avx2_rtm () from /usr/lib/libc.so.6
The interesting part comes when it is running as intended on my pc (Arch linux, amd cpu), and it does not on my laptop (Arch linux, intel cpu).
There are multiple problems in your code:
you do not test the return value of fopen(). If the file cannot be open, InputFile will be a null pointer and fscanf() will have undefined behavior.
fscanf(InputFile, "%s", help); will write beyond the end of the help array if the word in the file has 256 bytes or more. Use this instead:
fscanf(InputFile, "%255s", help);
or possibly:
fgets(help, sizeof help, InputFile);
and test for failure to read the file contents.
strncpy is not your friend: strncpy(CLIENTS_BOOK_ARRAY[i], token, MAX_SIZE_OF_ARRAYS) will not null terminate the string if it happens to be longer than MAX_SIZE_OF_ARRAYS - 1 bytes. Do not use strncpy, use strncat, snprintf or strlcpy if available instead.
the loop does not stop at the end of the 2D array: you should check that i < MAX_SIZE_OF_ARRAYS in the while test.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#define CLIENT_SIZE 100
#define CLIENT_NUMBER 100
#define CLIENTS_BOOK "client_book.txt"
static char client_book[CLIENT_NUMBER][CLIENT_SIZE];
int get_clients_string(void) {
int n = 0;
char buf[256];
FILE *InputFile = fopen(CLIENTS_BOOK, "r");
if (InputFile == NULL) {
fprintf(stderr, "error opening %s: %s\n",
CLIENTS_BOOK, strerror(errno));
return -1;
}
if (fgets(buf, sizeof buf, InputFile)) {
char *token = strtok(help, ",\n");
while (n < CLIENT_NUMBER && token != NULL) {
client_book[n][0] = '\0';
strncat(client_book[n], token, CLIENT_SIZE - 1);
token = strtok(NULL, ",");
n++;
}
} else {
fprintf(stderr, "%s: no clients\n", CLIENTS_BOOK);
}
fclose(InputFile);
return n;
}

Deleting a redundant parameter results in a segmentation fault, seemingly for no reason

The following program finds and deletes words that begin and end with the same character. It works just fine, except I decided to take the code for printing result text in from deleteWords() and put it inside of main(). Therefore, the *fpOut parameter in became redundant in deleteWords(). Deleting the parameter results in
/bin/sh: line 1: 1371 Segmentation fault: 11 ./main duom.txt rez.txt make: *** [main] Error 139
However if I compile it and run it any third parameter (e.g. int useless argument instead of FILE *fpOut), it works without errors.
Has anybody have a clue what could be causing this problem?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int checker (char zodis[]) {
size_t last = strlen(zodis);
if (zodis[0] == zodis[last-1])
return 0;
return 1;
}
void memAlloc (char **text, char **buffer, FILE **fp, char *fileName) {
int fileLength;
*fp = fopen(fileName, "r");
fseek(*fp, 0L, SEEK_END);
fileLength = fseek(*fp, 0L, SEEK_SET);
*text = malloc(fileLength * sizeof(char));
*buffer = malloc(fileLength * sizeof(char));
}
void deleteWords (FILE *fp, int anyUselessParameter, char *buffer) {
char *text;
while (fscanf(fp, "%s", text) == 1) {
if (checker(text)) {
printf("%s ", text);
sprintf(buffer + strlen(buffer), "%s ", text);
}
}
printf("\n");
}
int main(int argc, char *argv[]) {
FILE *fp, *fpOut;
int anyUselessParameter;
char *text, *buffer, *inputFileName = argv[1], *outputFileName = argv[2];
if (argc < 2)
return 0;
fpOut = fopen(outputFileName, "w");
memAlloc(&text, &buffer, &fp, inputFileName);
deleteWords(fp, anyUselessParameter, buffer);
fputs(buffer, fpOut);
fclose(fp);
fclose(fpOut);
free(text);
return 0;
}
char *text;
while (fscanf(fp, "%s", text) == 1) {
scanf needs the buffer to be allocated. Here it dereferences an uninitialized pointer text and writes to it. scanf tries to write to text[0], text[1].. and so on, so accesses text out of bounds and undefined behavior happen.
*buffer = malloc(fileLength * sizeof(char));
...
sprintf(buffer + strlen(buffer), "%s ", text);
buffer is uninitialized, so strlen(buffer) will result in some undefined value. Explicitly initialize buffer[0] = '\0' if you wish to use strlen later. Also you don't include memory for terminating '\0' character inside your buffer.
As you are trying to read the file into a buffer, that is allocated using the file size
if (fread(buffer, fileLenght, 1, fp) != fileLength) { /* handle error */ }
If you have to, use snprintf instead of sprintf just to be safe. snprinttf(buffer+strlen(buffer), fileLength - strlen(buffer), ...);
Also, try to never use scanf without specifing field length inside %s modifier. You can try:
char text[256]; // or other maximum word length
while (fscanf(fp, "%255s", text) == 1) {
As you already have allocated memory for the file, you can use it as a parameter to scanf, if you have to. One would need to prepare the format string for scanf as argument - it is a bit hard. See below:
for (;;) {
// prepare scanf %s format modifier to use with printf to write to buffer end
char fmt[20];
size_t buffer_size = fileLenght;
size_t free_in_buffer = buffer_size - strlen(buffer);
snprintf(fmt, 20, "%%%ds", free_in_buffer);
// we will write here: up to free_in_buffer
char *in = buffer + strlen(buffer);
if (fscanf(fp, fmt, in) != 1) break;
// we now check the last readed word form the file
if (!checker(in)) {
// if the last readed word is bad, we can revert it
in[0] = '\0'
}
}
This is wrong:
fileLength = fseek(*fp, 0L, SEEK_SET);
Per POSIX:
RETURN VALUE
The fseek() and fseeko() functions shall return 0 if they
succeed.
Otherwise, they shall return -1 and set errno to indicate the error.

Program crashing when reading blank line - c

I recently started working with files and i'm experiencing an error. I have a txt. file with the following strings:
a|10
b|5
My problem is when im reading the blank line, somehow it crashes even when i have the condition in the code. When debugging i can see that the line receives a "\n" but program doesnt recognize it in the condition and it crashes.
void delete_prod(void)
{
FILE *pfile;
char line[21];
char *buffer;
char *ptr;
char produto_nome[21];
char produto_quantidade[21];
char quantidade_nova[21];
char teste[21];
char barra_linha[]="\n";
buffer = (char *) malloc(1000*sizeof(char));
memset(buffer, 0, 1000*sizeof(char));
ptr = buffer;
printf("material:");
scanf("%s",teste);
pfile = fopen("registos.txt", "r");
while(!feof(pfile))
{
int i=0;
for(i; i<21;i++)
{
line[i] = 0;
}
fgets(line, 21, pfile);
if(line != NULL || line != "\n")
{
strcpy(produto_nome, strtok(line ,"|"));
strcpy(produto_quantidade, strtok(NULL, "|"));
if((strcmp(produto_nome,teste) == 0))
{
//DO THE REST OF THE WORK HERE
printf("HERE");
}
else
{
printf("ERROR");
}
}
}
fclose(pfile);
}
Have been researching here but didnt find anything that fixes my problem.
Thanks in advance and i hope i made myself clear explaining the problem.
consider fgets for all input.
strpbrk can be used to see if the line contains a |.
sscanf can parse the line to see if there are two values.
void delete_prod(void)
{
FILE *pfile;
char line[21];
char *buffer;
char *ptr;
char produto_nome[21];
char produto_quantidade[21];
char quantidade_nova[21];
char teste[21];
char barra_linha[]="\n";
buffer = (char *) malloc(1000*sizeof(char));
memset(buffer, 0, 1000*sizeof(char));
ptr = buffer;
printf("material:");
fgets ( teste, sizeof teste, stdin);
teste[strcspn ( teste, "\n")] = '\0';//remove newline
pfile = fopen("registos.txt", "r");
while( fgets ( line, sizeof line, pfile))
{
if( strpbrk ( line, "|"))//the line contains a |
{
//sscanf for two items
result = sscanf ( line, "%20[^|]|%20s", procuto_nome, produto_quantidade);
if(result == 2) {
if((strcmp(produto_nome,teste) == 0))
{
//DO THE REST OF THE WORK HERE
printf("HERE");
}
else
{
printf("ERROR");
}
}
else {
printf ( "ERROR line did not contain two values\n");
}
}
else {
printf ( "ERROR line does not contain |\n");
}
}
fclose(pfile);
}
Your condition of checking blank line is not correctly coded.
Change
line != "\n"
to
line[0] != '\n'
Because this condition was not correct, it was always getting satisfied. Later inside the if block strtok was returning null because there was no pipe symbol in the empty line. So effectively, you were passing null to the strcpy function which was crashing your program.

Split a string that I read from a file

I have a file like this
GET /index.html k
GET /docencia.html k
GET /ejemplo.html k
and I want to read it line by line and split it up with this delimiter " " but is giving me this error: segmentation fault(core dumped) and I don't know what to try.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char ordenes[150];
char *orden[3];
char *token;
int tok;
FILE *fp;
fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("File error");
exit(1);
}
while (feof(fp) == 0) {
fgets(ordenes, sizeof(ordenes), fp);
printf("%s \n", ordenes);
token = strtok(ordenes, " ");
tok = 0;
while (token != NULL) {
orden[tok] = strdup(token);
tok++;
token = strtok(NULL, " ");
}
printf("\n%s\n", orden[0]);
printf("\n%s\n", orden[1]);
printf("\n%s\n", orden[2]);
}
fclose(fp);
}
The error shows when I call the first strdup. If I try to print the token just after I call the first strtok, it fails too (the same segmentation fault core dumped) so I guess the problem is with the strtok.
You do not include <string.h>, so the compiler applies the default argument promotions on the signature of strtok, in particular it considers that strtok returns an int.
So the compiler will apply an operator of coercion from int to pointer to char at the assignment
token = strtok(ordenes, " ");
and this assignment will be compiled as
token = (int->char*) strtok(ordenes, " ");
There are multiple problems in your code:
As alinsoar diagnosed with a sharp eye, you do not include <string.h>. strtok is not defined, the compiler must assume it returns an int, which it does not, and this int is silently converted to a char *. The code generated invokes undefined behavior and will most likely crash on 64-bit targets. You should compile with all warnings enabled to let the compiler help avoid this kind of silly mistake. gcc -Wall -W or clang -Weverything...
You do not check if command line arguments have been passed to your program before calling fp = fopen(argv[1], "r");. If no arguments are passed, argv[1] is a null pointer.
while (feof(fp) == 0) is incorrect, read Why is “while ( !feof (file) )” always wrong? . You should instead write while (fgets(ordenes, sizeof(ordenes), fp)) {...
You do not check if tok < 3 before storing token into the orden array. If the line has more than 3 fields, you will cause a buffer overflow.
You do not check if 3 tokens were indeed found before printing all 3 entries in orden. This too might invoke undefined behavior, especially if fgets() failed to read a line, which you do not check.
Here is an improved version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char ordenes[150];
char *orden[3];
char *token;
int i, tok;
if (argc < 2) {
fprintf(stderr, "Missing command line argument\n");
exit(1);
}
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open input file %s: %s\n",
argv[1], strerror(errno));
exit(1);
}
while (fgets(ordenes, sizeof(ordenes), fp)) {
printf("%s", ordenes);
token = strtok(ordenes, " ");
for (tok = 0; tok < 3 && token != NULL; tok++) {
orden[tok] = strdup(token);
token = strtok(NULL, " ");
}
for (i = 0; i < tok; i++) {
printf("%s\n", orden[i]);
free(orden[i]);
}
printf("\n");
}
fclose(fp);
return 0;
}
For starters you should change the condition in the outer loop statement the following way
while ( fgets(ordenes, sizeof(ordenes), fp) != NULL )
The condition in the inner loop should be written at least like
while ( tok < 3 && token != NULL) {
The tokens should be outputted in a loop and the allocated memory must be freed. For example
for ( int i = 0; i < tok; i++ )
{
printf("\n%s\n", orden[i]);
free( orden[i]);
}
You can do the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void play_with_token(char *token, char const *delim)
{
if (token == NULL)
return;
printf(" %s", token);
play_with_token(strtok(NULL, delim), delim);
}
int main(int argc, char *argv[])
{
if (argc != 2)
return 1;
FILE *fp = fopen(argv[1], "r");
if (fp == NULL)
return 1;
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, fp)) != -1) {
printf("parsing line :");
char const *delim = " ";
play_with_token(strtok(line, delim), delim);
printf("\n");
}
free(line);
fclose(fp);
}
try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
char ordenes[150];
char *orden[3];
char *token;
int tok;
FILE *fp;
fp = fopen (argv[1], "r");
if(fp==NULL){
printf("File error");
exit(1);
}
while(fgets(ordenes, sizeof(ordenes), fp)){
printf("%s\n",ordenes);
token = strtok(ordenes, " ");
tok = 0;
while (token != NULL){
orden[tok++] = strdup(token);
token = strtok(NULL," ");
}
printf("\n%s\n",orden[0]);
printf("\n%s\n",orden[1]);
printf("\n%s\n",orden[2]);
free(orden[0]);free(orden[1]);free(orden[2]);
}
fclose(fp);
}

How to search for specific lines that starts with a string in a file

I need help with this little program I am trying to make.
There is .txt file:
namas house
katinas cat
suo dog
skaicius number
I want to find a line which begins with specific word and then prints second word of that line.
For example, user enters word katinas. Program looks through file, finds line that begins with katinas and finally prints.
What I have so far:
int main()
{
char word;
printf("Enter your word: ");
scanf("%s", &word);
FILE *fp;
fp = fopen("data.txt", "r+");
char buffer[256];
while (fgets(buffer, sizeof buffer, fp) != NULL && atoi(buffer) != word)
;
if (feof(fp))
{
printf(&buffer);
}
fclose(fp);
return 0;
}
Thank you.
There were several mistakes in the code as pointed out elsewhere. This answer will find whole words so for example "suo" but not "su".
#include<stdio.h>
#include<string.h>
int main()
{
char word[256]; // adequate string space (not single char)
char buffer[256];
char *sptr;
FILE *fp;
int found = 0;
printf("Enter your word: ");
scanf("%s", word); // requires a string pointer (note no &)
fp = fopen("data.txt", "r"); // removed "+"
if (fp) {
while (fgets(buffer, sizeof buffer, fp) != NULL) {
sptr = strtok(buffer, " \t\r\n");
if (sptr && strcmp(sptr, word) == 0) {
sptr = strtok(NULL, " \t\r\n");
if (sptr) {
printf("%s\n", sptr);
found = 1;
break;
}
}
}
fclose(fp);
}
if (!found)
printf ("%s not found\n", word);
return 0;
}
You could use a simple logic, just like using a 'for' to search for the word and right after you find the specific word that you want, continue with the 'for' until find a blank space (use ' ' to determinete the end and the beginning of a word) then print out all the letters until find the next blank ' '. This should work just fine.
char word; is a single char which can't store lines; should be an array in order to read a line.
atoi(buffer) != word you are comparing an int (returned by atoi()) with a pointer(array name gets converted into a pointer here). I really don't see the purpose of this.
You don't need to check if end of file has been reached. You just loop through the file line-by-line and check for your string.
Calling printf without format specifier is not safe and you are also passing char (*)[256] whereas printf expects a const char*.
You should also error checking on fopen().
Use a standard prototype for main() such as: int main(void)
After correcting all these, the code would be simplified to:
#include<stdio.h>
#include<string.h>
int main(void)
{
char word[256] = {0};
char buffer[256] = {0};
FILE *fp;
printf("Enter your word: ");
scanf("%s", word);
fp = fopen("data.txt", "r+");
if (!fp) { /* error */}
while ( fgets(buffer, sizeof buffer, fp) )
{
if( strstr(buffer, word) == buffer )
printf("Found: %s\n", buffer);
}
return 0;
}
There's no library function to find if a string "starts with" in C. I am using strstr to achieve that. If there's a match and it's equal to the starting address of the buffer, then it starts with word. Because strstr returns to a pointer to the first match.
#include <stdio.h>
int main(void){
char buffer[256];
char word[256], second_word[256];
char format[256];
FILE *fp;
printf("Enter your word: ");
scanf("%255[A-Za-z]", word);
sprintf(format, "%s %%255s", word);
fp = fopen("data.txt", "r");
while (fgets(buffer, sizeof buffer, fp) != NULL) {
if (sscanf(buffer, format, second_word) == 1) {
printf("%s\n", second_word);
break;//continue;?
}
}
fclose(fp);
return 0;
}

Resources