strstr() causing a segmentation fault error - c

The objective here is to take a whole text file that I dump into a buffer and then use the strcasestr() function to find the pointer of the word I am looking for within my buffer. It constantly gives me the segmentation fault error. At first, I thought it may be size so I tried with smaller sizes but it doesn't work either. The function only works with strings I create inside the actual code (ex : char * bob = "bob"; char * bobsentence = "bob is cool"; strstr(bobsentence, bob);). Which leads me to believe it has something to do with the fgets(). Any help is appreciated, really stuck on this one.
#define _GNU_SOURCE //to use strcasestr
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void textEdit(char *path, char *word){
printf("%s\n", path);
FILE *textFile;
//FILE *locationFile;
//FILE *tempFile;
char counter[1024];
int count = 0;
textFile = fopen(path, "r+");
//locationFile = fopen(path, "r+");
//opens file to read and write and opens temp file to write
if( textFile == NULL){ //|| tempFile == NULL || locationFile == NULL) ) {
printf ("\nerror\n");
return;
}
// SECTION : ALLOCATES MEMORY NEEDED FOR COPY TEXT IN ARRAY
// finds number of lines to estimate total size of array needed for buffer
while((fgets(counter, sizeof(counter), textFile)) != NULL){
count++;
}
fclose(textFile);
FILE *tempFile = fopen(path, "r+");
count *= 1024;
printf("%d %zu\n",count, sizeof(char));
char *buffer = malloc(count); //1024 is the max number of characters per line in a traditional txt
if(buffer == NULL){ //error with malloc
return;
}
// SECTION : DUMPS TEXT INTO ARRAY
if(fgets(buffer, count, tempFile) == NULL){
printf("error");
} //dumps all text into array
printf("%s\n", buffer);
char * searchedWord;
while((searchedWord = strcasestr(buffer, word)) != NULL){
}
fclose(tempFile);
//fclose(locationFile);
free(buffer);
}

It looks that you forgot to initialize count variable to 0:
int count = 0;
You increment it and it can contain any random value, even negative.
Also, note that your utilization of strstr doesn't look correct. The function returns the pointer to first occurrence that matches. Note, that it doesn't remember already found matches, so if match exists it should loop forever in this loop. Instead it should look like:
char *pos = buffer;
while((pos = strcasestr(pos, word)) != NULL){
searchedWord = pos;
/* do something with searchedWord but remember that it belongs to
allocated buffer and can't be used after free() */
pos++;
}

Related

Copy lines from file to char *array[]?

Hi need a little bit of help here. I have a file with 5 lines and I want to put this lines into an array of type char *lines[5]; but I can't figure it out why the following isn't working.
#include <stdio.h>
#include <string.h>
int main(void) {
FILE *fp = fopen("name.txt", "r");
char *str;
char *list[5];
int i = 0;
while (fgets(str, 100, fp) != NULL) // read line of text
{
printf("%s", str);
strcpy(list[i], str);
i++;
}
}
As the commenters stated, you need to create an array (which is nothing more than a space in the memory) of a sufficient size to store your string. One approach to solve your problems is the following, note the comments:
#include <stdio.h>
#include <string.h>
int lines(FILE *file); //try to format the code according to some standard
int main(void) {
FILE *fp = fopen("name.txt", "r");
char list[5][100]; //make sure you allocate enough space for your message
// for loop is more elegant than while loop in this case,
// as you have an index which increases anyway.
// also, you can make sure that files with more than 5 lines
// do not break your program.
for(int i = 0; i<5 ;++i )
{
if(fgets(list[i], 100, fp) == NULL){
break;
}
//list[i] is already a string, you don't need an extra copy
printf("%s", list[i]);
}
}

Read a file specified as an argument and return its' lines

I have an exercise in which I have to read a file containing strings and I have to return the content using one/multiple arrays (this is because the second part of this exercise asks for these lines to be reversed, I'm having problems - and therefore ask for help - with the input).
So far, I have this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LENGTH 1024
int main(int argc, char *argv[]){
char* input[LENGTH];
if(argc==2){
FILE *fp = fopen(argv[1], "rt");
if(fp!=NULL){
int i=0;
while(fgets(input, sizeof(input), fp)!=NULL){
input[i] = (char*)malloc(sizeof(char) * (LENGTH));
fgets(input, sizeof(input), fp);
i++;
}
printf("%s", *input);
free(input);
}
else{
printf("File opening unsuccessful!");
}
}
else{
printf("Enter an argument.");
}
return 0;
}
I also have to check whether or not memory allocation has failed. This program in its' current form returns nothing when run from the command line.
EDIT: I think it's important to mention that I get a number of warnings:
passing argument 1 of 'fgets' from incompatible pointer type [-Wincompatible-pointer-types]|
attempt to free a non-heap object 'input' [-Wfree-nonheap-object]|
EDIT 2:
Example of input:
These
are
strings
... and the expected output:
esehT
era
sgnirts
In the exercise, it's specified that the maximum length of a line is 1024 characters.
You probably want something like this.
Comments are in the code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LENGTH 1024
int main(int argc, char* argv[]) {
if (argc == 2) {
FILE* fp = fopen(argv[1], "rt");
if (fp != NULL) {
char** lines = NULL; // pointer to pointers to lines read
int nboflines = 0; // total number of lines read
char input[LENGTH]; // temporary input buffer
while (fgets(input, sizeof(input), fp) != NULL) {
char* newline = malloc(strlen(input) + 1); // allocate memory for line (+1 for null terminator)
strcpy(newline, input); // copy line just read
newline[strcspn(newline, "\n")] = 0; // remove \n if any
nboflines++; // one more line
lines = realloc(lines, nboflines * sizeof(char*)); // reallocate memory for one more line
lines[nboflines - 1] = newline; // store the pointer to the line
}
fclose(fp);
for (int i = 0; i < nboflines; i++) // print the lins we've read
{
printf("%s\n", lines[i]);
}
}
else {
printf("File opening unsuccessful!");
}
}
else {
printf("Enter an argument.");
}
return 0;
}
Explanation about removing the \n left by fgets: Removing trailing newline character from fgets() input
Disclaimers:
there is no error checking for the memory allocation functions
memory is not freed. This is left as an exercise.
the way realloc is used here is not very efficient.
you still need to write the code that reverses each line and displays it.
You probably should decompose this into different functions:
a function that reads the file and returns the pointer to the lines and the number of lines read,
a function that displays the lines read
a function that reverses one line (to be written)
a function that reverses all lines (to be written)
This is left as an exercise.

Trying to read an unknown string length from a file using fgetc()

So yeah, saw many similar questions to this one, but thought to try solving it my way. Getting huge amount of text blocks after running it (it compiles fine).
Im trying to get an unknown size of string from a file. Thought about allocating pts at size of 2 (1 char and null terminator) and then use malloc to increase the size of the char array for every char that exceeds the size of the array.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *pts = NULL;
int temp = 0;
pts = malloc(2 * sizeof(char));
FILE *fp = fopen("txtfile", "r");
while (fgetc(fp) != EOF) {
if (strlen(pts) == temp) {
pts = realloc(pts, sizeof(char));
}
pts[temp] = fgetc(fp);
temp++;
}
printf("the full string is a s follows : %s\n", pts);
free(pts);
fclose(fp);
return 0;
}
You probably want something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define CHUNK_SIZE 1000 // initial buffer size
int main()
{
int ch; // you need int, not char for EOF
int size = CHUNK_SIZE;
char *pts = malloc(CHUNK_SIZE);
FILE* fp = fopen("txtfile", "r");
int i = 0;
while ((ch = fgetc(fp)) != EOF) // read one char until EOF
{
pts[i++] = ch; // add char into buffer
if (i == size + CHUNK_SIZE) // if buffer full ...
{
size += CHUNK_SIZE; // increase buffer size
pts = realloc(pts, size); // reallocate new size
}
}
pts[i] = 0; // add NUL terminator
printf("the full string is a s follows : %s\n", pts);
free(pts);
fclose(fp);
return 0;
}
Disclaimers:
this is untested code, it may not work, but it shows the idea
there is absolutely no error checking for brevity, you should add this.
there is room for other improvements, it can probably be done even more elegantly
Leaving aside for now the question of if you should do this at all:
You're pretty close on this solution but there are a few mistakes
while (fgetc(fp) != EOF) {
This line is going to read one char from the file and then discard it after comparing it against EOF. You'll need to save that byte to add to your buffer. A type of syntax like while ((tmp=fgetc(fp)) != EOF) should work.
pts = realloc(pts, sizeof(char));
Check the documentation for realloc, you'll need to pass in the new size in the second parameter.
pts = malloc(2 * sizeof(char));
You'll need to zero this memory after acquiring it. You probably also want to zero any memory given to you by realloc, or you may lose the null off the end of your string and strlen will be incorrect.
But as I alluded to earlier, using realloc in a loop like this when you've got a fair idea of the size of the buffer already is generally going to be non-idiomatic C design. Get the size of the file ahead of time and allocate enough space for all the data in your buffer. You can still realloc if you go over the size of the buffer, but do so using chunks of memory instead of one byte at a time.
Probably the most efficient way is (as mentioned in the comment by Fiddling Bits) is to read the whole file in one go (after first getting the file's size):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
int main()
{
size_t nchars = 0; // Declare here and set to zero...
// ... so we can optionally try using the "stat" function, if the O/S supports it...
struct stat st;
if (stat("txtfile", &st) == 0) nchars = st.st_size;
FILE* fp = fopen("txtfile", "rb"); // Make sure we open in BINARY mode!
if (nchars == 0) // This code will be used if the "stat" function is unavailable or failed ...
{
fseek(fp, 0, SEEK_END); // Go to end of file (NOTE: SEEK_END may not be implemented - but PROBABLY is!)
// while (fgetc(fp) != EOF) {} // If your system doesn't implement SEEK_END, you can do this instead:
nchars = (size_t)(ftell(fp)); // Add one for NUL terminator
}
char* pts = calloc(nchars + 1, sizeof(char));
if (pts != NULL)
{
fseek(fp, 0, SEEK_SET); // Return to start of file...
fread(pts, sizeof(char), nchars, fp); // ... and read one great big chunk!
printf("the full string is a s follows : %s\n", pts);
free(pts);
}
else
{
printf("the file is too big for me to handle (%zu bytes)!", nchars);
}
fclose(fp);
return 0;
}
On the issue of the use of SEEK_END, see this cppreference page, where it states:
Library implementations are allowed to not meaningfully support SEEK_END (therefore, code using it has no real standard portability).
On whether or not you will be able to use the stat function, see this Wikipedia page. (But it is now available in MSVC on Windows!)

Read a XML file and print the tags using C

There is a XML file and I have to identify, store and print the Unique tags present in it.
Example XML File:
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
I need to store note,to,from,heading,body etc.. tags in an array and print them afterwards.
Below is the code I tried, but facing issue while checking and removing / from the closing tag to identify duplicate tags.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*Max number of characters to be read/write from file*/
#define MAX_CHAR_FOR_FILE_OPERATION 1000000
int read_and_show_the_file()
{
FILE *fp;
char text[MAX_CHAR_FOR_FILE_OPERATION];
int i;
fp = fopen("/tmp/test.txt", "r");
if(fp == NULL)
{
printf("File Pointer is invalid\n");
return -1;
}
//Ensure array write starts from beginning
i = 0;
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while( (fgets(&text[i++],sizeof(char)+1,fp) != NULL) && (i<MAX_CHAR_FOR_FILE_OPERATION) ) ;
const char *p1, *p2, *temp;
temp = text;
while(p2 != strrchr(text, ">"))
{
p1 = strstr(temp, "<");
p2 = strstr(p1, ">");
size_t len = p2-p1;
char *res = (char*)malloc(sizeof(char)*(len));
strncpy(res, p1+1, len-1);
res[len] = '\0';
printf("'%s'\n", res);
temp = p2 + 1;
}
fclose(fp);
return 0;
}
main()
{
if( (read_and_show_the_file()) == 0)
{
printf("File Read and Print is successful\n");
}
return 0;
}
I also tried the strcmp to check the value of if(strcmp(res[0],"/")==0) to check the closing tag, but not working, showing segmentation fault. No example is present on C. Please review and suggest.
Below is the output:
'note'
'to'
'/to' //(Want to remove these closing tags from output)
'from'
'/from' //(Want to remove these closing tags from output)
and so on..
Segmentation fault also occurring.
This addresses just one of the segmentation faults in your question:
You have to give string to strcmp, you can not just give character (res[0]). But since you don't need to compare string, why don't you just compare the first character (res[0]=='/')?

String / char * concatinate, C

Am trying to open a file(Myfile.txt) and concatenate each line to a single buffer, but am getting unexpected output. The problem is,my buffer is not getting updated with the last concatenated lines. Any thing missing in my code?
Myfile.txt (The file to open and read)
Good morning line-001:
Good morning line-002:
Good morning line-003:
Good morning line-004:
Good morning line-005:
.
.
.
Mycode.c
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
/* Define a temporary variable */
char Mybuff[100]; // (i dont want to fix this size, any option?)
char *line = NULL;
size_t len=0;
FILE *fp;
fp =fopen("Myfile.txt","r");
if(fp==NULL)
{
printf("the file couldn't exist\n");
return;
}
while (getline(&line, &len, fp) != -1 )
{
//Any function to concatinate the strings, here the "line"
strcat(Mybuff,line);
}
fclose(fp);
printf("Mybuff is: [%s]\n", Mybuff);
return 0;
}
Am expecting my output to be:
Mybuff is: [Good morning line-001:Good morning line-002:Good morning line-003:Good morning line-004:Good morning line-005:]
But, am getting segmentation fault(run time error) and a garbage value. Any think to do? thanks.
Specify MyBuff as a pointer, and use dynamic memory allocation.
#include <stdlib.h> /* for dynamic memory allocation functions */
char *MyBuff = calloc(1,1); /* allocate one character, initialised to zero */
size_t length = 1;
while (getline(&line, &len, fp) != -1 )
{
size_t newlength = length + strlen(line)
char *temp = realloc(MyBuff, newlength);
if (temp == NULL)
{
/* Allocation failed. Have a tantrum or take recovery action */
}
else
{
MyBuff = temp;
length = newlength;
strcat(MyBuff, temp);
}
}
/* Do whatever is needed with MyBuff */
free(MyBuff);
/* Also, don't forget to release memory allocated by getline() */
The above will leave newlines in MyBuff for each line read by getline(). I'll leave removing those as an exercise.
Note: getline() is linux, not standard C. A function like fgets() is available in standard C for reading lines from a file, albeit it doesn't allocate memory like getline() does.

Resources