history in implementation of shell get segmentation fault - c

So I wrote some code to implement the shell (Linux, GCC, C language) and it all works but from some reason the code crashes when I added the history option:
It really doesn't (the other code) so I'll put here only what you need.
The problem is when I type quit after one old command that need to be saved in the history and when I type quit it just crushes with segmentation fault (core dumped).
The history is saved in a structure of a linked list, string of command and the node for the next node, also I saved the head in the main. The point is that I want to save only 15 last commands, and I don't care about the others, so every time I want to print the list I just moved on the first 15 nodes in the loop.
When I debugged with GDB I saw that the line the code crashes is the line after he add the first command the the history but the current line is really not related to the history:
main:
int main()
{
history_ll* top;
char userInput [CHOICE_LENGTH];
char buff[PATH_MAX];
int flag=1;
cmdLine * head;
while (flag)
{
getcwd(buff, PATH_MAX);
printf("%s:~$ ",buff);
fgets(userInput,MAX_INPUT, stdin);
userInput[strlen(userInput)-1]=0;
historyAdder(userInput,&top);
if(strcmp(userInput,QUIT_OPTION)==0) //segmentation fault here!
{
flag=0;
}
else
{
//doesn't matter
}
}
return 0;
}
the historyAdder looks like this:
void historyAdder(const char *command,history_ll** top)
{
history_ll* node;
strcpy(node->command,command);
node->command[strlen(command)]=0;
if(historyLength!=0)
{
node->next= *top;
}
else
{
node->next= NULL;
}
*top = node;
historyLength++;
}
NOTE: historyLength is a global variable
This is the structure:
typedef struct history_ll{
char command[CHOICE_LENGTH];
struct history_ll *next;
}history_ll;
Thank you helpers!

There are at least two important issues in this code.
One is that buffer length might ne too short when you read from stdin:
definition:
char userInput [CHOICE_LENGTH];
but usage is:
fgets(userInput,MAX_INPUT, stdin);
You should use same buffer size or assert MAX_INPUT is less or equal CHOICE_LENGTH.
Second, you trigger undefined behavior by dereferencing uninitialised pointer here:
void historyAdder(const char *command,history_ll** top)
{
history_ll* node;
strcpy(node->command,command); /* bad... */

Here (and in the lines following)
void historyAdder(const char *command,history_ll** top)
{
history_ll* node;
strcpy(node->command,command);
...
the code dereferences an uninitialised pointer: node Doing so invokes UB and mostly likely crashes the program.

This is probably your problem:
char userInput [CHOICE_LENGTH];
...
fgets(userInput,MAX_INPUT, stdin);
Unless CHOICE_LENGTH is greater than or equal to MAX_INPUT, fgets can write past the end of the userInput array, which will corrupt memory, leading to a crash. However, since you did not show a complete program that I could compile for myself and watch crash, I can't be sure.
Two pieces of advice for you:
You're on Linux, so you have getline. Use it instead of fgets and you won't have to worry about input buffer sizes.
Whenever you have a program that is crashing with segmentation faults, the first thing you reach for should be valgrind. Very often, valgrind will reveal that the real bug is nowhere near where you thought it was.

Related

Segmentation Fault on calling a function

When I call the print_linklist function I am getting a segmentation fault. Here is the function definition:
//will display the node in a nice string
char * term_to_string(term_t * term){
int exp = term->exponent;
int coef = term->coefficient;
return ("%dx^%d", coef, exp);
}
**//will print the list using the nodde_to_string method
void print_linklist(node_t * curr){
printf("entering print to list!!!");
node_t * current = curr;
while(current != NULL){
printf("%s +", term_to_string(curr->term));
current = current->next_node;
}
}**
And here is the main method where it is being called:
/* This is your main file */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"common.h"
#include"buildlinklist.h"
#include"printandcombine.h"
int main() {
node_t * node_ptr = NULL;
node_t * new_node_ptr=NULL;
printf("NAME: SAMPLE OUTPUT\n");
/* Build linklist */
read_objects(&node_ptr);
/* Print the link list */
printf("Original: \n");
print_linklist(node_ptr);
/* Combine like terms in the link list and craeate a new link list */
new_node_ptr=combine_like_terms(node_ptr);
printf("\nCombined: : ");
/* Print new combine linklist */
print_linklist(new_node_ptr);
printf("\nNAME: SAMPLE OUTPUT\n");
free(node_ptr);
free(new_node_ptr);
return 0;
}
After the function is called I get "zsh: segmentation fault ./project1". I don't even get the "entering print to list!!!" to print from the print_linklist method.
return ("%dx^%d", coef, exp);
That's not doing what you seem to think it's doing (what I think you think it's doing is to return a string created by some sort of printf functionality).
However, the comma operator in something like a, b evaluates both a and b, but the result is b. The n-variant, like a, b, c, d, evaluates everything and returns the last one (d).
Hence you are returning exp as if it was a character pointer. It almost certainly isn't (since you're trying to printf it with %d) so, if you treat it as such, hilarity may ensue.
Well, less hilarity and more crashing/weirdness, but you get the idea :-)
You could create strings in heap memory and pass them around but it's sometimes difficult for newcomers to the language to do that safely. Instead, I would suggest simply printing the thing within the function, with something like:
void print_term(const term_t *term, const char *after){
printf("%dx^%d%s", term->coefficient, term->exponent, after);
}
void print_linklist(node_t *curr){
puts("entering print to list!!!");
node_t *current = curr;
while (current != NULL){
print_term(curr->term, " +");
current = current->next_node;
}
}
You'll notice my "entering print to list" statement is subtly different to yours in that it uses puts, which appends a newline character to the end (you could do that explicitly, with \n, if you wanted to stick with printf).
Since standard output is line-buffered for terminal devices, the reason you're not seeing that is almost certainly due to the fact your code is crashing (as per this answer) before it flushes. In that case, unflushed data is likely to just disappear.
There could be a number of reasons you are getting a segmentation fault but trying to print the list is not one of them. If your read_objects() declaration is like this read_objects(node_t * curr) then you shouldn't pass as an argument the address of the pointer
read_objects(&node_ptr);
This should be read_objects(node_ptr);
Also, if you want to iterate through the list and print it you should create a pointer to the head of the list in the main() function node_t *head = NULL;
and pass it as a parameter in the print_linklist(head);.
After that, make *current point at the head of the list node_t * current = head;.
That way you are starting printing the nodes from the start. You should also check if the list is empty.
I don't even get the "entering print to list!!!" to print from the print_linklist method.
printf doesn't cause anything to be printed to the screen. It just copies a string into a buffer to be printed at some later time. If you want to force the buffer to be printed, you can call fflush. As mentioned in comments, if stdout is directed to an interactive device, including a \n in the output string will generally also cause the buffer to be flushed to the actual output device.
After the function is called I get "zsh: segmentation fault ./project1".
This probably happens in term_to_string if you call it with an invalid pointer argument, when it tries to dereference its argument.

Why is this conditional statement not working in C? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to create a program in C that is able to create a list of characters (using a linked list) input by the user, and follow these commands: insert (adds a new character to the list), remove (clears the list and deletes all elements), print (prints the current contents of the list) and exit (closes the program). In order for it to work, the user must enter the command to execute first. For instance, if they type 'insert', they will be prompted to enter a character, if they type 'print', the program will print the list, and so on.
To approach this, I basically declared a char[] variable called command. Which represents the user's text input. After receiving the input, the program will compare the command string to the following strings: insert, remove, print, and exit, and if the strings match, then the program will execute the command that the string corresponds to (refer to the main below):
#include <stdio.h>
#include <stdlib.h>
struct linked_list
{
char data;
struct linked_list* next;
};
void insert(struct linked_list** head, char input);
void removed(struct linked_list** head);
void printed(struct linked_list* head);
void insert(struct linked_list** head, char input) {
int x;
x = ("%d",input);
if (x < 97 || x > 122) {
printf("The character you entered is invalid, please use the insert command and try again\n");
}
else {
struct linked_list* newNode = (struct linked_list*) malloc(sizeof(struct linked_list));
struct linked_list* lastNode = *head;
newNode->data = input;
newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
return;
}
while (lastNode->next != NULL) {
lastNode = lastNode->next;
}
lastNode->next = newNode;
}
}
void removed(struct linked_list** head) {
struct linked_list* current = *head;
struct linked_list* next;
while(current != NULL) {
next = current->next;
free(current);
current = next;
}
*head = NULL;
}
void printed(struct linked_list* head) {
while (head != NULL) {
printf("%c ", head->data);
head = head->next;
}
printf("\n");
}
int main(int argc, char *argv[]) {
char command[] = "";
char inserts[] = "insert";
char removes[] = "remove";
char prints[] = "print";
char exits[] = "exit";
char input;
struct linked_list* head = NULL;
int done = 1; //Variable used to keep the loop going until the user types 'exit'
printf("Welcome, please use the commands 'insert', 'remove', 'print' or 'exit' to use the program\n");
while (done == 1) {
scanf("%s", &command);
int result1 = strcmp(command,inserts);
int result2 = strcmp(command,removes);
int result3 = strcmp(command,prints);
int result4 = strcmp(command,exits);
if (result1 == 0) {
printf("Enter a char: ");
scanf("%s", &input);
insert(&head, input);
result1 = 1;
}
else if (result2 == 0) {
removed(&head);
result2 = 1;
}
else if (result3 == 0) {
printed(head);
result3 = 1;
}
else if (result4 == 0) {
printf("The program will close now");
done = 0;
}
else {
printf("Unrecognized command, please try again\n");
}
}
return 0;
}
The solution I came up with works perfectly for the commands insert, remove, and print. However, for some reason I can't quite understand it doesn't work for exit, it will only work if and only if exit is the first command you enter (which doesn't make sense, since why would you exit a program without even using it). There are no typos or other apparent errors. You can compile the code and see for yourself. What might be causing this issue? Why does it work for three of the command words but not for one?
Thanks in advance
UPDATE: After messing around with the code a little bit, I realized none of the suggestions provided were the issue. I simply changed my loop statement to be : else if (strcmp(command,"exit")==0) and it worked perfectly
x = ("%d",input);
involves the comma operator. The left operand "%d" is evaluated (to itself, since a literal string, then discarded) and the right operand input is evaluated and result of that comma operator.
So x becomes input
You may want to spend a dozen of minutes reading about scanf or about getchar. It can fail. You should handle both failure and success (with some test).
My personal recommendation : enable all warnings and debug info in your compiler. With GCC, compile with gcc -Wall -Wextra -g. Improve your code to get no warnings. Then use your debugger (e.g. GDB) to understand the behavior of your program.
Of course you will spend some time reading the documentation of your compiler and of your debugger.
Don't forget to spend some time reading a good book on the C programming language. Refer also to this C reference. Study also for inspiration the source code of existing free software (like GNU bash) coded in C. You will learn a lot by reading existing reviewed C code.
You may also want to read something about parsing techniques. You could consider (if your teacher allows that) using parser generators like GNU bison (which generates C code).
Be aware that in 2021 UTF-8 is used everywhere.
Be scared and avoid undefined behavior.
In some cases, a program appears to work, but does not. Read some C standard (like n1570) explaining it. I guess your program has several buffer overflows.
You could also (if your teacher allows it) use tools like the Clang static analyzer, valgrind or the address sanitizer
The reason your commands aren't working as intended is that you declare zero-length string literal:
char command[] = "";
then read user input into it:
scanf("%s", &command);
The user input isn't going to fit into zero characters, so it's going to overwrite something else in memory, likely something important.
You need to declare an actual buffer that's large enough to hold the largest expected input, something like this:
char command[10];
You also need to clear or initialize that buffer, perhaps using memset(command, 0, sizeof(command));
Something similar happens with input. It's declared as char but then you read a string (%s) into it:
scanf("%s", &input);
Even if you only type one character, scanf still has to store a terminating NUL, so it will clobber something else in memory.
With all these buffer overwrites going on, what the program actually does, and why exit only works as the first command, is anybody's guess.

Saving argv[1] to a char* variable causes seg fault when passed to separate function

I'm trying to rewrite a stripped down version of the "ls" command in C. I originally had everything being done in my main() which worked fine and resulted in no seg faults. Literally all I did was copy and paste the bulk of my main into a new function, which I called into_array() (to do the actual saving the directory entries into my own self-made file_info structs to be analyzed later on). Now, when I try to run it sunny-day code -- just a.out /home which is supposed to sort and print the names, I get the full sorted list, followed by a seg fault, and since the only thing I changed was the direct use of argv[1] to the use of a char *pathname, I'm assuming it has something to do with that. Below is the code:
void into_array (char *arg)
{
//asume correct input, default
DIR *myDIR;
struct dirent *mydirent;
struct stat *mystat;
myDIR = opendir(arg);
int count = 0;
while ((mydirent = readdir(myDIR)) != NULL)
{
count++;
}
rewinddir(myDIR);
struct file_info **file_info_array = malloc(sizeof(struct file_info*)*count);
int i = 0;
while ((mydirent = readdir(myDIR)) != NULL)
{
stat(arg, mystat);
file_info_array[i] = malloc(sizeof(struct file_info));
struct file_info *file_i = info_store(mydirent, mystat, 's');
file_info_array[i] = file_i;
i++;
}
file_info_array[i] = NULL;
int is_closed = closedir(myDIR);
send_to_sort(file_info_array, 'n');
print(file_info_array);
}
int main (int argc, char *argv[])
{
into_array(argv[1]);
return 0;
}
This can't work:
struct stat *mystat;
...
stat(arg, mystat)
stat requires a pointer to storage where it can store the result, mystat isn't initialized. Easiest is to just do
struct stat mystat;
stat(arg, &mystat)
You're writing past your array with file_info_array[i] = NULL;. You haven't allocated storage for that last element, you should allocate storage for count + 1 elements if you need the last element to be a NULL pointer.
Other things you need to do, otherwise you're setting yourself up to not be able to figure out what happens when your code fails:
opendir() can fail, make sure you check that it succeeds.
stat() can fail, make sure you check that it succeeds.
malloc() can fail, make sure you check that it succeeds.
Someone might not pass an argument to your program, check for that.
There's a chance there's equally many errors in your other functions, you should audit those too.
That your original program did not segfault does not prove that it was wholly correct. If it exhibits undefined behavior, then that behavior can turn out to be exactly the behavior you hoped and expected, but you can't rely on that being the same from run to run, much less after you modify the code (without resolving the UB).
Your program contains calls to several functions whose definitions you do not provide. Any of those might invoke UB. The function you did provide, however, certainly does invoke UB: it writes past the end of dynamic array file_info_array, because you allocate exactly enough space for all the entries, but not for the NULL at the end.
As #nos first observed, you also have a problem related to variable mystat, and you code very optimistically, assuming the program arguments are correct and that none of your function calls fail.

My program can only use malloc() to allocate memory a few times

I wrote a binary search tree to store some sorted words. As is often the practice, I do this by allocating new block of memory for the binary tree every time a new word come in. But, strangely, I can only allocating new memory for the binary search tree twice, which means that at the first and second time everything was fine but the program crash at the third memory allocation.
Here is my code:
inputWord.c
/* I pass in the firstNode, and the word I wanna store, and its quantity as argument*/
int inputWord(BSTnode* Node,char* word,int num){
BSTnode* ptr=Node; //ptr was defined to track the location of the node.
while(1){
if(stricmp(word,ptr->data)>0){
/*If the current node already have a rightchild then ptr move to it, and do comparison again*/
if(ptr->rightchild!=NULL){
ptr=ptr->rightchild;
printf("Moving to another (right) node now!!\n");
continue;
}
/*If the current node have no rightchild, then make a new one for it and store the word and its quantity*/
else{
ptr->rightchild=malloc(sizeof(BSTnode));
if(!(ptr->rightchild))
return 1;
ptr=ptr->rightchild;
ptr->rightchild=NULL;
ptr->leftchild=NULL;
strcpy(ptr->data,word);
ptr->num=num;
break;
}
}
else if(stricmp(word,ptr->data)<0){
/*it's all the same as the rightchild part*/
if(ptr->leftchild!=NULL){
ptr=ptr->leftchild;
continue;
}
else{
ptr->leftchild=malloc(sizeof(BSTnode));
if(!(ptr->leftchild))
return 1;
ptr=ptr->leftchild;
ptr->leftchild=NULL;
ptr->rightchild=NULL;
strcpy(ptr->data,word);
ptr->num=num;
break;
}
}
/*If the word have already been stored in the tree, print out this message*/
else{
fprintf(stdout,"It is exactly the same word!!\n");
return 0;
}
}
return 0;
}
I have make some necessary comments above to help you understand my intention.Hopefully that would help.
As you can see, that function was pretty straight and simple. And it did work for the first two invokation.But it crash when invoked the third time!!(always the third time).
So I made some test. And now I am pretty sure that it crash at the line
ptr->leftchild=malloc(sizeof(BSTnode));
(make it clear that the data offirstNode is initialize with "" for comparison. And I pass in the word "The" first and "Project" second and "Gutenberg" third. And the structure of BSTnode is
typedef struct BSTnode{
char data[20];
struct BSTnode* leftchild;
struct BSTnode* rightchild;
int num;
}BSTnode;
)
How I make that test is listed as below. (It is the same code, only with some extra print statement for test)
int inputWord(BSTnode* Node,char* word,int num){
printf("Enter inputWord() successfully!!\n");
BSTnode* ptr=Node;
while(1){
if(stricmp(word,ptr->data)>0){
if(ptr->rightchild!=NULL){
ptr=ptr->rightchild;
printf("Moving to another (right) node now!!\n");
continue;
}
else{
printf("I need a new rightchild!!\n");
ptr->rightchild=malloc(sizeof(BSTnode));
printf("New rightchild created successfully!!\n");
if(!(ptr->rightchild))
return 1;
ptr=ptr->rightchild;
ptr->rightchild=NULL;
ptr->leftchild=NULL;
printf("......In line 27 now!!\n");
strcpy(ptr->data,word);
printf("Copied successfully!!!..In line 29 now!!\n");
ptr->num=num;
fprintf(stdout,"New data '%s' successfully inserted into a new (right) node at %p (value of pointer)\n",word,ptr);
break;
}
}
else if(stricmp(word,ptr->data)<0){
if(ptr->leftchild!=NULL){
ptr=ptr->leftchild;
printf("Moving to another (left) node now!!\n");
continue;
}
else{
printf("I need a new left child!!!\n");
ptr->leftchild=malloc(sizeof(BSTnode));
printf("New leftchild created successfully!!\n");
if(!(ptr->leftchild))
return 1;
ptr=ptr->leftchild;
ptr->leftchild=NULL;
ptr->rightchild=NULL;
printf("......In line 47 now!!\n");
strcpy(ptr->data,word);
printf("Copied successfully!!!..In line 51 now!!\n");
ptr->num=num;
fprintf(stdout,"New data '%s' successfully inserted into a new (left) node at %p (value of pointer)\n",word,ptr);
break;
}
}
else{
fprintf(stdout,"Nothing else to insert!!\n");
return 0;
}
}
return 0;
}
As you can see, with some print statements telling me where have I been, I can be sure where the program crash.
Any idea why it always crash at the third time?
#######################################################################3
main.c
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include "wordCount.h"
void prompt(BSTnode*,FILE*);
char arr[20]={0};
int main()
{
BSTnode* firstNode=malloc(sizeof(BSTnode));
firstNode->leftchild=NULL;
firstNode->rightchild=NULL;
strcpy(firstNode->data,"");
firstNode->num=0;
FILE* fs=fopen("testfile.txt","r");
if(!fs){
printf("Failed to open fiel!!\n");
return 2;
}
while(1){
if(ferror(fs))
perror("there is a error in fs in the beginning of while loop!\n");
prompt(firstNode,fs);
}
return 0;
}
void prompt(BSTnode* Node,FILE* fs){
int i=0;
printf("Please select\n1.find and input a word into the binary tree\n2.print only one data\n3.Exit\n");
if(scanf("%d",&i)!=1){
printf("scanf failed!!\nplease input a valid number!!\n");
//fflush(stdin);
return;
}
getchar();
switch(i){
case 1:
{
memset(arr,'\0',20); //since the "arr" is used to hold the newWord founded and returned, it should be clear first every time
char* newWord=findWord(fs);
int totalNumberOfTheWord=wordCount(fs,newWord);
inputWord(Node,newWord,totalNumberOfTheWord);
break;
}
case 2:
printOneNode(Node);
break;
case 3:
exit(0);
default:
printf("Please input a valid number!(1-3)");
}
}
Also, the wordCount.h:
#ifndef WORDCOUNT_H
#define WORDCOUNT_H
#include<stdlib.h>
#include<stdio.h>
typedef struct BSTnode{
char data[20];
struct BSTnode* leftchild; //if less than, put it on the left
struct BSTnode* rightchild; //if greater than, on the right
int num;
}BSTnode;
int inputWord(BSTnode*,char*,int);
char* findWord(FILE*);
int wordCount(FILE*,char*);
int printOneNode(BSTnode*);
#endif
The function prompt() is used to prompt the user to decide whether to continue word-searching.
#####################################################################3
full source code:
wordCount.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "wordCount.h"
int wordCount(FILE* fs,char* word)
{
int num=0;
rewind(fs);
size_t n1=sizeof(word);
size_t n2=strlen(word);
char* buff=malloc(n1) ;
if(buff==NULL)
return 1;
memset(buff,'\0',n1);
/* I count the word by moving byte by byte and do comparison*/
if (fs != NULL) {
if (n2 == fread(buff, 1,n2, fs)) {
do {
if (strnicmp(buff,word,n2) == 0)
num++;
memmove(buff, buff+1,n2-1);
} while (1 == fread(buff+n2-1, 1, 1, fs));
// I think I might optimize
// this using KMP algorithm
}
}
free(buff);
return num;
}
findWord.c
#include<string.h>
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include "wordCount.h"
extern char arr[20];
char* findWord(FILE* fs)
{
static long pos=0;
fseek(fs,pos,SEEK_SET);
if(ferror(fs)){
perror("fseek() failed!!!\n");
fprintf(stderr,"fseek() failed in file %s\n",__FILE__);
exit(EXIT_FAILURE);
}
char chr[1]={0};
bool flag1=false;
bool flag2=false;
while((1==fread(chr,1,1,fs))&&(!(flag1==false&&flag2==true))){
// This would make the findword() function
// find only a single word once
if(chr[0]!=32){
strncat(arr,chr,1);
flag2=true;
flag1=true;
}
else
flag1=false;
}
/*the key method that I use to find a new word is that I use two 'bool' flags: flag1 and flag2.
*Only when the "arr" is filled only with character, not a single space, will the flag1 be false and flag2 be true, thus breaking the while loop*/
pos=ftell(fs)-1;
//maybe everytime you use "fseek()", "ftell()", the
//file-position will move one byte ahead.
return arr;
}
printOneNode.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"wordCount.h"
int printOneNode(BSTnode* Node){
BSTnode* ptr=Node;
while(1){
printf("Select which side of node do you want to print now(l/r)?(q for quit) ");
char a;
getchar(); //this is used to consume the newline character left
//fflush(stdin);
if(scanf("%c",&a)!=1){
printf("scanf failed!!");
return 1;
}
switch(a){
case 'l':
{
if(ptr->leftchild!=NULL){
ptr=ptr->leftchild;
printf("\t%s\n",ptr->data);
}
else
printf("There is no more leftchild\n");
break;
}
case 'r':
{
if(ptr->rightchild!=NULL){
ptr=ptr->rightchild;
printf("\t%s\n",ptr->data);
}
else
printf("There is no more rightchild!\n");
break;
}
case 'q':
return 0;
default:
return 0;
}
}
}
The function findWord() is used to find a new word for insertion. For example, if there is string This is a lovely place... in the textfile.txt, then the findWord() would first find out a word This and then is secondly and then a thirdly, etc. (This is the reason why I define the pos as a static variable to keep track of the location.)
The function wordCount() is used to count out how many time those the word returned by findWord() appear in the testfile.txt.
The function printOneNode() is used to print out the data of one single node according to the user's willingness. I designed this function but haven't use it yet, which mean that in the prompt() function I always choose to "find and input a new word into the binary search tree"). So this may not the reason that cause my program to crash "occasionally".
As summary, my routine is:
prompt the user asking whether to find and insert a new word( always yes)
find a new word in the testfile.txt using findWord()
count the number using wordCount()
insert it into the binary search tree using inputWord()
Repeat that.
I cannot make this program smaller any more to make it more understandable, because it have to find a word and count it insert it. But you can ignore that printOneNode() function, to some extent.
As for the testfile.txt, I have posted the link below at the comment area. Thanks
edit: This is an amendment to my previous post (found below), detailing the more severe issues found in this code.
In wordCount there is a buffer overflow. Buffer overflows are UB.
You're allocating n1 bytes for buff to point at. By chance, do you happen to know how many bytes that is? Perhaps you should check, and then answer this to yourself: How many bytes can you store in that object?
You're then attempting to read n2 bytes into buff. Which is greater, n1 or n2? Have you looked at that? What happens if you try to fit 24 eggs into a carton that only holds 12?
I think the problem here is that you don't understand the sizeof operator; it isn't a function... Rather, it is an operator much like the &address-of and the -negation operator, except that sizeof operates on the type of (or denoted by) an expression; it evaluates to the size of objects of that type.
To clarify, in the following fragment of code, n1 is sizeof (char *), which is probably not what you intended.
int wordCount(FILE* fs,char* word)
{
int num=0;
rewind(fs);
size_t n1=sizeof(word);
size_t n2=strlen(word);
char* buff=malloc(n1);
inputWord seems to operate under the impression that word points to a string, however that value seems to come from findWord in your program, which doesn't necessary produce a string (because it uses strncat). More undefined behaviour! Is this surprising?
Previous answer:
Firstly, this code doesn't even compile. You're missing a semicolon immediately following inputWord(Node,newWord,totalNumberOfTheWord) within prompt. Perhaps you haven't noticed the errors, and you're running an out-of-date binary which we don't have the source code for?
Secondly, even if this code were to compile, there are a number of instances of undefined behaviour such as:
Null pointer dereferences occur when malloc returns NULL and you attempt to modify the object which NULL points to as a result. e.g. BSTnode* firstNode=malloc(sizeof(BSTnode)); followed immediately by firstNode->leftchild=NULL;. Perhaps you could declare firstNode like so: BSTnode firstNode = { 0 }; and create a pointer to it using &firstNode... After all, you really should choose the most appropriate storage duration rather than defaulting to malloc every time. On that note, I highly recommend separating your allocation logic from your data structure logic; if you need further elaboration, consider how scanf is designed.
fflush(stdin);. Whenever you use a function for the first time, you should always read and understand the manual very carefully... and that's not just to provide insight on how you should be designing your functions. If you had read and fully understood this fflush manual prior to using fflush, you would have never used this problematic code. Consider using something like scanf("%*[^\n]"); getchar(); in its place.
In a few places you're using the %p format directive, which expects a void * pointer as a corresponding argument. The corresponding argument you're providing, however, is of type struct BSTnode *. According to the fprintf manual, "If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined."
Even if you don't fix these undefined behaviours, this code may coincidentally work on your system when you provide dummy functions in place of findWord and wordCount. However, it's not required to work the same way on all systems, which means for you the crash might occur where for us it doesn't. Fix those problems.
Those problems indicate that your findWord and wordCount functions aren't necessarily trustworthy and foolproof, either; they might work for you in one setting whilst failing for you in another, or worse yet, perhaps they're stale too! You should have verified that the problem is where you think it is by providing dummy functions in their places. That is, after all, part of the process of creating an MCVE so that your question doesn't get closed.
No, I won't be interested in starting a bounty on this question because it's of extremely poor quality; as I previously mentioned, this question relies upon syntactically erroneous code compiling correctly, so we can't reproduce the result you see. Even if we fix the syntax errors, we'd have to fill in the blanks (that's your work) which introduces an aspect of uncertainty into any possible answers. About the only thing I am interested in starting for this question is the process of having it closed.

Copying data between two struct pointers giving segmentation fault

I am getting a segmentation fault when trying to copy the contains of a pointer to a struct to another pointer.
My struct:
typedef struct State {
char alphabets[2][6];
struct State *PREV; /*this points to the previous state it came from*/
struct State *NEXT; /*this points to the next state in the linked list*/
int cost; /*Number of moves done to get to this position*/
int zero_index;/*this holds the index to the empty postion*/
char *move[2];/*this holds the move that was done to get to this state*/
} State;
Memory allocation method:
State *memAllocator() {
State *p = (State*)malloc(sizeof(State));
if (p == NULL) {
printf("Malloc for a new position failed");
exit(1);
}
return p;
}
Here' an example of my Structs Alphabets
CANAMA
PANAL_
I have a randomize function that gives me the two possible moves of the state. The two moves for the above state would be
CANAM_
PANALA
AND
CANAMA
PANA_L
In my randomize state function I copy the contains of my current state and then put it in the new state.
But here is the problem, I'm doing a breadth first search and trying to find out the shortest distance from the one state to another. In the process of doing I get pretty far in the search. But then it gives a segmentation fault at line where I copy the contains of current state to a new state.
I tried memcpy as well, but it gives the same segmentation fault. Here are the lines:
*new_state=*current_state;
/*memcpy(new_state, current_state, sizeof(State));*/
So, is the way I am copying my memory incorrect that is causing the problem. But if thats the case then why does it go for a while and then gives out a segmentation fault. Please help.
Here's a link to my full code. Full Code
Looks like at least one of new_state and current_state is null. Best to change your printfs from printf("If exception below then problem in swapN\n"); to printf("If exception below then problem in swapN: %p %p\n", current_state, new_state1); to see where this happens; but at least one possibility is the following:
printf("If exception below then problem in swap3\n");
new_state1 = swap(empty_index/10, (empty_index%10)-1,current_sta te, new_state1);
printf("If this prints problem not in swap\n");
if (new_state1 != NULL){
//... [REMOVED FOR CLARITY]
return;
}
/*Go East*/
/*printf("Step %d, move %c west\n",current_state->alphabets[empt y_index/10][(empty_index%10)+1]);*/
printf("If exception below then problem in swap4\n");
new_state1 = swap(empty_index/10, (empty_index%10+1),current_state, new_state1);
Notice that the second call to swap() will ALWAYS have new_state1 be NULL (because you already returned it if's not null!)

Resources