When I compile and run this program on Windows/Eustis I am not getting any errors or warnings.
The basic function of the program is to read in an input text file(source code) and strip out C-style comments /*........*/ to a file cleaninput.txt.
It works on Windows. However, when run on Eusis I get this:
gcc -o out.x a2.c
./out.x
*** stack smashing detected ***: ./out.x terminated
Aborted
I have tried compiling with the command
gcc -fno-stack-protector -o out.x a2.c
./out.x
*** Error in './out.x': double free or corruption (out): 0x09670440 ***
Aborted
Is there a program or utility I can use to figure this out?
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
#define MAX_DEC_LENGHT 11
#define MAX_INTEGER 99999
#define MAX_LINE_WIDTH 100 //used in the struct below defines how wide a instruction can be per line
FILE *fp;
typedef struct input{
char line[MAX_LINE_WIDTH];
struct input *next;
}input;
void scanFile();
struct input *Push(struct input *temp2, char Buff[MAX_LINE_WIDTH]);
void printClean(struct input *temp);
int Get_No_Lines();
void freeme(struct input* ptr);
const char *strip_comments(char input[MAX_LINE_WIDTH]);
int main(){
int x = Get_No_Lines();
scanFile(x); //will read in the input and produce cleaninput.txt, get_no_lines is used to tell the program later how long the input text file is
return(0);
}
/*
Take in an integer N, which represents how many lines there are in the text file, which is used in scanning into a linked list of each line
calls for the print clean input function
Currently not returning anything
*/
void scanFile(int n){
fp = fopen("input.txt", "r");
struct input*temp = NULL;
int i;
for(i=0;i<n;i++){
char Buff[MAX_LINE_WIDTH];
fgets(Buff,MAX_LINE_WIDTH,fp); //fgets is by far the easiest solution i found to scanning in line by line, the linked list is there for unlimited input lenght
temp = Push(temp,Buff); //push the value of fgets onto the linked list
}
printClean(temp);
freeme(temp); //at this point we call the printClean input function
fclose(fp);
}
/*
Take in the the pointer to a linked list, and place the value buff into the structs line segment,
Basic function is linked list push to end
*/
struct input *Push(struct input *temp2, char Buff[MAX_LINE_WIDTH]){
struct input *temp=(struct input*)malloc(sizeof(struct input));
struct input *current = temp2;
strcpy(temp->line,Buff);
temp->next= NULL;
if(temp2==NULL){
return(temp); //base case if null
}
while(current->next!=NULL){
current = current->next; //insert to back of list
}
current->next = temp; //link the new node
return(temp2);
}
/*
The main driver function for stripping the comments out of the input text file,
calls the strip_comments function and places the result back into the struct, then prints to the file stream
currently not returing anythig, shouldnt need to, will be checked later -MM
*/
void printClean(struct input *temp){
fp = fopen("cleaninput.txt", "w");
while(temp!=NULL){
char t[MAX_LINE_WIDTH];
strcpy(t,strip_comments(temp->line)); //copy the contents of strip_comments into t, and then copy the contents of t into temp->line
strcpy(temp->line, t); //yeah im not sure why i need to strcpy's but it wouldnt work without them \_(?)_/¯
fputs(temp->line, fp);
temp=temp->next;
}
fclose(fp);
}
const char *strip_comments(char input[MAX_LINE_WIDTH]){
char output[100];
int i=0;
int x =0;
int inComment = 0; // a boolean variable to let the case statment change behavior in the while loop
while(i<=MAX_LINE_WIDTH){
if(inComment==1){
if(input[i]=='*' && input[i+1]=='/'){
inComment=0;
i++; //end the comment, and increment the counter up two to clear hte comment
i++;
}
}
if(inComment==0){
if(input[i]=='/'&& input[i+1]=='*'){ //condtion to enter the comment switch
inComment=1;
}else{
output[x] = input[i]; //if not in the comment and last check was not in comment push the value of input[i] to output[x] increment x
x++;
}
}
i++;
}
char *rtn = output;
return(rtn); //return the input free of comments, currently cannot handle multi_line comments
}
/*
Used for the scanning function, its sole purpose is to let the program know how many lines there are in the input text file
*/
int Get_No_Lines(){
fp = fopen("input.txt", "r");
int ch, number_of_lines = 0;
do
{
ch = fgetc(fp);
if(ch == '\n')
number_of_lines++; //if the scanner gets to a \n charecter increment
} while (ch != EOF);
if(ch != '\n' && number_of_lines != 0) // needs to be checked, method was adopted from the internet
number_of_lines++;
if(number_of_lines==0){ //i added this case in when we get a one line input that the user has not hit the /n or enter key
number_of_lines =1;
}
fclose(fp);
return(number_of_lines);
}
void freeme(struct input* ptr){
struct input *temp;
while(ptr!=NULL){
temp=ptr->next;
strcpy(ptr->line,"");
free(ptr);
ptr=temp;
}
}
You are returning a pointer to the local variable char output[100];, which invokes undefined behavior. Returning a pointer to a local variable is always a severe bug.
Instead, pass the output buffer as a parameter to the function and leave the allocation to the caller.
Can a local variable be accessed outside its scope?
Related
i am trying to read and print one value in a linked list , but my program does not give any output, i have tryed checking where the program is failing to execute , after the first scanf the code is not printing anything, what might be the reason for that?
code is as followed:
#include<stdlib.h>
#include<stdio.h>
void display();
struct ll{
int val;
struct ll* address;
};
struct ll *new=NULL,*start=NULL,*present=NULL;
int main(void)
{
int num;
scanf("%d",&num);
//reading ll
new=(struct ll*) malloc(sizeof(struct ll));
new->val=num;
new->address=NULL;
if(start==NULL)
{
start=new;
present=new;
}
else
{
present->address=new;
present=new;
}
//calling display func to display the contents of ll
display();
}
void display()
{
present=start;
// displaying.
while (present!=NULL)
{
printf("%d",present->val);
present=present->address;
}
printf("%d",present->val);
}
I have encoded my comments interspersed into your code. I have commented the last statement in function display(), to make it run properly. I have also commented the cast to malloc() (for the given reasons in the code) I have also made some aesthetic changes to make the code more readable. You can add spaces to improve readability of the code, as they don't change the compiler produced code, so please, use enough spaces to make your code more readable (I've done this also to show who it is more readable now):
#include <stdlib.h>
#include <stdio.h>
void display(void);
struct ll {
int val;
struct ll *address;
};
struct ll *new = NULL,
*start = NULL,
*present = NULL;
int main(void)
{
int num;
scanf("%d", &num);
//reading ll
/* Never cast the returned value of malloc() This allows to
* detect if you have properly #include'd the header file and
* avoids other dificult to find errors. malloc() returns a
* void * pointer, so it will be automatically converted to
* any other pointer type without risk. */
new = /* (struct ll*) */ malloc(sizeof(struct ll));
new->val = num;
new->address = NULL;
if(start == NULL)
{
start = new;
present = new;
}
else
{
/* this is never executed, as start == NULL at program
* start. */
present->address = new;
present = new;
}
//calling display func to display the contents of ll
display();
/* while it is not necessary for main() it is normal for a function
* that is defined to return an int value, to return something, so
* I added the following statement: */
return 0;
}
void display(void)
{
present = start;
// displaying.
while (present != NULL)
{
printf("%d",present->val);
present = present->address;
}
/* as you have moved present in a while loop until the while
* condition is false, at this point you must assume the
* condition is false (so present == NULL) and you are trying to
* dereference a NULL pointer below */
/* printf("%d", present->val); */
}
Now your program will run and show the only value (I recommend you to put a \n character at the end of the printf() call, to put the printed data in a line by itself.
The program should read a simple text file and store the data ( name and id) into a linked list.
This is the linked list:
struct Prova
{
char nome[16];
int id;
};
typedef struct Node {
struct Prova struttura;
struct Node * next;
}TNodo;
typedef TNodo* Nodo;
This function creates the linked list:
void NewList(struct Prova p, Nodo * pp)
{
Nodo temp;
temp = (Nodo)malloc(sizeof(struct Node));
temp->struttura = p;
temp->next = *pp;
*pp = temp;
}
This is the function i wrote to read the file:
void Load(Nodo *pp)
{
FILE *f;
struct Prova p;
char * buffer;
if(!(f = fopen(PATH, "r")))
{
perror("Error");
exit(-1);
}
buffer = malloc(sizeof(struct Prova));
while(fgets(buffer, sizeof(buffer), f))
{
if(sscanf(buffer, "%s%d", p.nome, &p.id) > 0)
{
NewList(p, pp);
}
}
free(buffer);
fclose(f);
}
The text file i'm trying to read is this:
Stefano 31
Paperino 23
Pippo 1
Pluto 14
The functions for displaying the list are these:
void View(struct Prova p)
{
printf("%s %d\n", p.nome, p.id);
}
void ViewList(Nodo nodo)
{
while(nodo != NULL)
{
View(nodo->struttura);
nodo = nodo->next;
}
The program compiles fine, but it outputs the data in a strange order.
Let me know if you need more info, i think it's all related to the function Load() which is the newest.
Main function is this:
int main()
{
int scelta;
struct Prova test;
Nodo lista = NULL;
do {
scelta = Menu();
switch (scelta)
{
case 1: Load(&lista); break
case 2: ViewList(lista); break;
default: scelta = 0;
}
} while (scelta != 0);
return 0;
}
For now the output is this:
The problem is occurring because of passing sizeof(buffer) to fgets(). buffer is a pointer and sizeof(buffer) will return either 4 or 8 based on underlying architecture 32 bit or 64 bit. Change this to:
while(fgets(buffer, sizeof(struct Prova), f))
as you are allocating sizeof(struct Prova) size to buffer.
This is also not the correct solution of the problem. Reason is-
Say, your file is having this data:
abcdefghijklmno 123456789
The name part is 15 character long which nome member can hold and id member can also hold the number 123456789 as it is less than INT_MAX. fgets read characters from the stream and the size of above-given data is 25 characters. In your code, you are allocating sizeof(struct Prova) size memory to buffer and size of struct Prova is 20 byte. Hence for the above-given data, buffer is not allocated enough memory to read the whole line in one go because the fgets reads until size-1 characters have been read or either a newline or the end-of-file is reached, whichever happens first. So, in this case, the partial line will be read and passed to sscanf() and rest of the line will be read in next iteration and passed to sscanf() which will give the incorrect results.
You should not allocate the memory to buffer based on the size of struct Prova. Instead, I would suggest taking buffer of some bigger size, like this (no need to allocate it dynamically):
char buffer[100];
ensure it should be bigger enough to accommodate a line of the file in one read of fgets or modify your code to not to fill p.nome and p.id until fgets hits newline character or EOF i.e. to make sure to read the whole line and then only sscanf() the p.nome and p.id.
Working on a project where I'm creating a linked list from items in a 2d array. The array has been populated correctly, but my method for creating the linked list is causing a segmentation fault. While trying to debug where the fault was occurring, I put a print statement one line above the method call, but the print statement never printed. But, if i commented out the method call, the print statement did print.
main()
{
struct String *list;
char words1[100][1000];
for(int i = 0; i < 100; i++)
words1[i][0] = '\0';
char *words2[100];
for(int i = 0; i < 100; i++)
words2[i] = words1[i];
char ** words = words2;
getStrings(words);
for(int i = 0; i < 100; i++)
{
if(words[i][0] == '\0') break;
printf("%s\n", words[i]);
}
printf("Creating list\n"); //**(RIGHT HERE)** <-----------
//createList(list, words);
//sortStrings(list);
showStrings(list);
return 0;
}
struct String
{
char *s;
struct String *next;
};
void createList(struct String * list, char **words)
{
list = NULL;
struct String *node;
int counter = 0;
while (1)
{
if (words[counter][0] == '\0') break;
printf("Adding: %s", words[counter]);
node = (struct String *) malloc(sizeof(struct String));
node->s = words[counter];
node->next = NULL;
list->next = node;
list = node;
counter++;
}
}
void getStrings(char **s)
{
int count = 0;
for(int i = 0; i < 1000; i++)
{
int ret = scanf("%[^;]", s[i]);
if(ret < 0) break;
count++;
getchar();
}
}
Why would a segmentation fault in the createList() method cause a function that should have been called before it to not execute (or at least not show up)?
Edit: Added getStrings() method to code.
printf function does not write data to standard output immediately, as it might be too slow to do. Instead it might collect data in an internal buffer of stdout object. Once buffer gets full (or sometimes when newline is reached) its content gets "flushed" (written to the underlying file). During normal execution this data is also written before program exits, but because your program gets terminated beforehand, it is not able to empty that buffer, losing data.
You can add fflush(stdout); statement after printf to force data to be written.
Normally when writing to terminal buffer is flushed at \n. I suspect you are writing to a pipe instead (might be your IDE redirects your program output).
You can read more abut file streams here: http://en.cppreference.com/w/cpp/io/c
And about fflush here: http://en.cppreference.com/w/cpp/io/c/fflush
You can also use setvbuf function to manipulate file object buffering: http://en.cppreference.com/w/cpp/io/c/setvbuf
main()
{
/* uninitialized list head must be initialized as NULL */
struct String *list = NULL;
. . .
void createList(struct String * list, char **words)
{
/* Value of list changing only in local scope, list must be a
`struct String **` type. */
list = NULL;
. . .
/* access to field on NULL pointer -> segmentation fault */
list->next = node;
I have a text file:
In 0 John 66
In 1 May 77
In 0 Eliz 88
Out 0
Out 0
I'm trying to parse this text file using scanf, and at the moment send the values after "In" to the add function, however I'm getting a seg fault when trying to do this.
I have some code here:
A struct in a seperate header file:
typedef Officer test;
typedef struct {
test tests[6];
int s;
} copList;
And this one:
typedef struct {
char name[25];
int id;
} Officer;
Then I have my main method
int main(void) {
FILE * ptr;
char buffer [500];
char * temp;
int pos;
int grade;
char * name;
copList * L;
ptr = fopen("test.txt","r");
if(ptr == NULL)
exit(1);
temp = malloc(sizeof(char)*10);
name = malloc(sizeof(char)*10);
L = malloc(sizeof(copList));
while(fgets(buffer,500,ptr) != NULL) {
sscanf(buffer,"%s %d %s %d\n",temp,&pos,name,&grade);
add(L->tests[pos],pos,L); //this gives me a seg fault
}
free(name);
free(temp);
free(L);
fclose(ptr);
return 0;
}
In a separate c file I have the add function.(Can't be changed)
void add(Test b, int pos, copList * L) {
//code to be added here later...
}
I've tried allocating different amounts of memory, but that didn't help. Also I noticed if I set a value to pos, in the while loop, before the add function call, I don't get a seg fault, but obviously that's not what I want, because the value wouldn't change. Any help would be much appreciated.
The main problem I see with your code is that it does not check the return value of sscanf -- if sscanf returns something other than 2 or 4, that means your input is something other than what you say it is. In addition, the arrays temp and name might overflow (on inputs other than what you show), which would cause undefined behavior. Finally, the spaces and \n in the sscanf format are wrong and should be removed (though they shouldn't actually cause any problems in this case.)
So you code should be something like:
while(fgets(buffer,500,ptr) != NULL) {
int count = sscanf(buffer,"%9s%d%9s%d",temp,&pos,name,&grade);
if (count != 2 && count != 4) {
fprintf(stderr, "Invalid input line: %s", buffer);
continue; }
... do stuff with temp and pos (only use name and grade if count == 4)
in this line:
add(L->tests[pos],pos,L);
the first parameter is a copy of the 'test' struct.
It is almost always a bad idea to pass a whole struct. Much better to just pass a pointer to the struct:
add( &(L->tests[pos]), pos, L );
Then, this line has a couple of problems:
void add(Test b, int pos, copList * L) {
1) 'Test' is a non-existent type, perhaps you meant: 'test'
2) 'b' is expecting a passed struct. as mentioned above,
it is (almost) always better to pass a pointer to a struct.
I am trying to write a program which will count the occurrence of words in a paragraph.
The logic I am following : I am using a linked list for the purpose. And I am searching sequentially - if new word encountered adding the word in the list, but if word already exist in the list increase its count flag.
//case insensitive string matching
int strcicmp(char const *a, char const *b)
{
int d;
for(;;a++,b++)
{
d=tolower(*a)-tolower(*b);
if(d!=0 || !*a)
return d;
}
}
//declare the linked list structure to store distinct words and their count
typedef struct node
{
char *word;
int count;
struct node *next;
} node;
node *ptr, *newnode, *first=NULL, *last=NULL;
void insertnewword(char *ch)
{
newnode=(node*)malloc(sizeof(node));
if(newnode == NULL)
{
printf("\nMemory is not allocated\n");
exit(0);
}
else
{
newnode->word=ch;
newnode->count=1;
newnode->next=NULL;
}
if(first==last && last==NULL)
{
first=last=newnode;
first->next=NULL;
last->next=NULL;
}
else
{
last->next=newnode;
last=newnode;
last->next=NULL;
}
}
void processword(char *ch)
{
int found=0;
//if word is already in the list, increase the count
for(ptr=first;ptr!=NULL;ptr=ptr->next)
if(strcicmp(ptr->word, ch) == 0)
{
ptr->count += 1;
found=1;
break;
}
//if it's a new word, add the word to the list
if(!found)
insertnewword(ch);
}
int main()
{
const char *delimiters=" ~`!##$%^&*()_-+={[}]:;<,>.?/|\\\'\"\t\n\r";
char *ch, *str;
str=(char*)malloc(sizeof(char));
ch=(char*)malloc(sizeof(char));
//get the original string
scanf("%[^\n]%*c", str);
//fgets(str, 500, stdin);
//get the tokenized string
ch=strtok(str,delimiters);
while(ch!=NULL)
{
//a, an, the should not be counted
if(strcicmp("a", ch)!=0 && strcicmp("an", ch)!=0 && strcicmp("the", ch)!=0)
processword(ch);
ch=strtok(NULL,delimiters);
}
//print the word and it's occurrence count
for(ptr=first; ptr!=NULL; ptr=ptr->next)
printf("%s\t\t%d\n",ptr->word,ptr->count);
return 0;
}
this seem to be working fine for few number of words, but if word count is more than 6-7, this program is encountering some problem.
Say input is : I am a good boy. I am a bad Boy.
Input should be
I 2
am 2
good 1
bad 1
boy 2
But what I am getting is
I 2
am 2
good 1
bad 1
(some garbage character) 1
I can always implement any other logic for the same problem, but I want to know the issue with this implementation.
Thanks in advance
I think the problem come from your scanf:
in the man scanf:
the next pointer must be a pointer to char, and there must be enough room for all the characters in the string, plus a terminating null byte
but in the top of your main, the allocation of your char array is juste one bite long:
str=(char*)malloc(sizeof(char));
I think it would be better to use function like getline
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
and setting lineptr pointing to NULL
I think your linked list implementation is not causing you the problems but your memory allocation is causing you the actual problems.
First memory allocation problem:
str=(char*)malloc(sizeof(char));
ch=(char*)malloc(sizeof(char));
Here str and ch should have memory to hold the complete word along with terminating null character but you have allocated only one byte(i.e. size of char)
Second memory allocation problem:
newnode->word=ch;
This code fragment is present in your insertnewword() function.
Here you have allocated memory to your new node but you have not allocated any memory to the char *word present inside new node. After that you are directly making newnode->word point to ch which is a local variable of main() function.
When you complete the first word and tokenize the input string further, ch contains next word from the string. Now this may corrupt data in your linked list as you have made newnode->word directly point to ch.
So please allocate memory to word field present in newnode and copy the contents of ch into it.
I hope this will solve your problem.