I have written a program that reads in words from a text file. There is one word per line. I need to find how many times each word repeats. To find this out so far i have read the words in from the file and placed them all in a dynamically allocated array of struct. My problem is that the program keeps segmentation faulting whenever i try to run it. I assume there is a problem with how i am dynamically allocating the data.
Code is as follows;
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
//struct
struct _data {
char *word;
int number;
};
//scan for size of file
int SCAN(FILE *data) {
int size = 0;
char s_temp[50];
while (1) {
fscanf(data, "%s", s_temp);
if (feof(data)) break;
size++;
}
return size;
}
//load content into struct
int LOAD(FILE *data, int size, struct _data *Wordstruct){
int i;
char temp[50];
for (i=0; i <size; i++){
fscanf(data, "%s", temp , &Wordstruct[i].word, &Wordstruct[i].number);
Wordstruct[i].word =calloc(strlen(temp), sizeof(char));
strcpy(Wordstruct[i].word, temp);
if(strcasecmp(Wordstruct[i].word, temp) ==0){
Wordstruct[i].number++;
}
}
return size;
}
//count how many times each word repeats
void COUNT(struct _data *Wordstruct, int size){
int i;
int count;
count =0;
char *word;
if (strcasecmp(Wordstruct[i].word, word)==0){
count++;
for(i=0; i<size; i++){
printf("%s\n",Wordstruct[i].word,"occurs:\t",count);
}
}
}
//main routine
int main(int argc, char *argv[]){
int size;
FILE *data;
struct _data *Wordlist;
if(argc <2){
printf("Not enough arguments\n");
}
else{
FILE *data= fopen(argv[1],"r");
size =SCAN(data);
LOAD(data, size, Wordlist);
COUNT(Wordlist, size);
}
return 0;
}
You haven't allocated memory for Wordlist. Add
Wordlist = malloc(size*sizeof(*Wordlist));
before the call to LOAD.
And, as pointed out by #BLUEPIXY in comments, change
Wordstruct[i].word =calloc(strlen(temp), sizeof(char));
to
Wordstruct[i].word =calloc(strlen(temp)+1, sizeof(char));
Change this:
Wordstruct[i].word =calloc(strlen(temp), sizeof(char));
To this:
Wordstruct[i].word =calloc(strlen(temp)+1, sizeof(char));
You need to account for NULL terminator, strlen() does not do that for you here.
Related
Below is my (incomplete) code for a merge sort project. This worked fine for the parts I have implemented until I switched from the 128 line test file to the 31 mb file that is supposed to be sorted. Now getting a segfault and I'm not sure what to do in order to solve this.
Removed some lines I believe are inconsequential because "mostly code".
struct Record {
char key[KEYSIZE+1];
char data[DATASIZE+1];
};
int threadCount;
int tiers;
static struct ThdArg {
int thdNum; // Thread number 0,1,2,3
struct Record * lowRec; // First record of group or first index of record
struct Record * hiRec; // Last record of group or last index of record
};
int lines;
int tiers;
void *threadFunc(void *var)
{
struct ThdArg temp2 = *((struct ThdArg*)var);
qsort((temp2.lowRec), lines/threadCount, sizeof(struct Record), comparator);
for(int k=0;k<tiers;k++)
if(temp2.thdNum%(int)(pow(2,k+1))==0)
{
qsort((temp2.lowRec), lines/(threadCount/(int)pow(2,k+1)), sizeof(struct Record),comparator);
}
}
int main(int argc, char **argv[])
{
if (argc!=2)
{
printf("Please enter a file name");
return 0;
}
threadCount =8;
tiers =(int)log2((double)threadCount);
pthread_t threads[threadCount];
FILE *recordFile=fopen(argv[1], "r");
char ch;
fseek(recordFile, 0, SEEK_END);
lines = ftell(recordFile);
fseek(recordFile, 0, SEEK_SET);
lines=lines/64;
struct Record recArr[lines];
char buffer[9];
char buffer2[57];
for(int j=0;j<lines;j++)
{
fgets(buffer, 9, recordFile);
for(int i=0;i<8;i++)
{
recArr[j].key[i]=buffer[i];
}
recArr[j].key[8]='\0';
fgets(buffer2, 57, recordFile);
for(int i=0;i<56;i++)
{
recArr[j].data[i]=buffer2[i];
}
recArr[j].data[57]='\0';
}
struct ThdArg temp[threadCount];
for(int i=0;i<threadCount;i++)
{
temp[i].thdNum = i;
temp[i].lowRec=&recArr[(lines/threadCount)*i];
temp[i].hiRec=&recArr[(lines/threadCount)*(i+1)-1];
pthread_create(&threads[i],NULL, threadFunc, (void *)&temp[i]);
}
for(int i=0;i<threadCount;i++)
{
pthread_join(threads[i], NULL);
}
}
The following line:
struct Record recArr[lines];
allocates memory on the stack. Its size is restricted.
If you read a file which can be be very big use malloc:
#include <stdlib.h>
typedef struct {
char key[KEYSIZE +1];
char data[DATASIZE +1];
}Record;
...
recArr = malloc(sizeof(Record) * lines);
...
free(recArr);
You can use the pointer like an array. (In fact, they are the same)
I want to store words from a pointer of char strings in a double linked list. My function for storing the words in the char strings works perfect, but when it comes to storing in the dll elements it doesn't work anymore. I can't understand if there is a problem in the declarative zone of the list (I am new to lists, we just did some theory on them in the class) or with the node changing pointer.
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
int number_of_words (FILE *f) {
char x[1024];
int i=0;
while (fscanf(f, " %1023s", x) == 1) {
i++;
}
return i;
}
void words (FILE *f, char *words[]) {
char x[1024];
int i=0;
while (fscanf(f, " %1023s", x) == 1) {
words[i]=strdup(x);
i++;
}
}
typedef struct node{
int freq;
char *word_string;
struct node *next;
struct node *prev;
}node;
int main(int argc, const char * argv[]) {
FILE *input=fopen(argv[1], "r+");
if(input==NULL) printf("error in reading from file");
else printf("reading works.\n");
int k=number_of_words(input);
char *word[k];
char *word_unique[k];
rewind(input);
words(input, word);
int j=0,l=0,s=0;
for(j=0;j<k;j++) {
for (l=0; l<j; l++){
if (strcmp(word[j],word[l])==0)
break;
}
if (j==l){
word_unique[s]=word[j];
s++;
}
}
int *word_freq[s];
for(j=0;j<s;j++){
word_freq[j]=0;
}
for(j=0;j<s;j++) {
for (l=j; l<k; l++){
if (strcmp(word_unique[j],word[l])==0)
word_freq[j]++;
}
}
char *aux=malloc(30*sizeof(char));
for(j=0;j<s;j++){
for(l=j+1;l<s-1;l++){
if(strcasecmp(word_unique[j], word_unique[l])>0)
{
strcpy(aux,word_unique[j]);
strcpy(word_unique[j],word_unique[l]);
strcpy(word_unique[l],aux);
}
}
}
node *head, *curr=NULL;
int i=0;
head=NULL;
for(i=0;i<k;i++){
curr=(node *)malloc(sizeof(node));
curr->word_string=word_unique[i];
curr->freq=word_freq[i];
curr->next=head;
head=curr;
}
while(curr) {
if(curr->word_string!=NULL) printf("%s:%d\n", curr->word_string, curr->freq);
curr = curr->next;
}
return 0;
}
The input file is a text file and it looks like this:
Everything LaTeX numbers for you has a counter associated with it. The name of the counter
is the same as the name of the environment or command that produces the number, except
with no. Below is a list of some of the counters used in LaTeX’s standard document styles
to control numbering.
When I tried to print the unique elements in alphabetical order with their frequency, it actually prints out in reverse order with 4x frequency they actually have. It also separates "numbering." from the others + a new line at the beginning which I don't know where it comes from. This is what it prints:
reading works.
0- :2098416
numbering.:4
you:4
with:4
used:4
to:4
the:4
The:4
that:4
styles:4
standard:4
some:4
same:4
produces:4
or:4
of:4
numbers:4
number,:4
no:4
name:4
list:4
LaTeX’s:4
LaTeX:4
it.:4
is:4
in:8
has:24
for:16
except:8
Everything:4
environment:4
document:8
counters:4
counter:8
control:8
command:4
Below:4
associated:4
as:4
a:4
\.:4
Program ended with exit code: 0
the code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
typedef struct word{
char word[20];
int occurrance;
} word;
int array_word_creator(word *array, FILE *fp);
void initialize(word array[], int max);
void comparator(word array[], int max, FILE *fp);
void printer(word array[], int max);
int main(int argc, char *argv[])
{
FILE *f_sent, *f_words;
word *array;
int arr_lenght=0;
if(argc!=3)
{
printf("Wrong argument number, please use NAME FILE1 FILE2;\n");
exit(EXIT_FAILURE);
}
if((f_sent=fopen(argv[1], "r"))==NULL||(f_words=fopen(argv[1], "r"))==NULL)
{
printf("Can't find or open the files, please check if the name is correct\n");
exit(EXIT_FAILURE);
}
arr_lenght=array_word_creator(array, f_words);
comparator(array, arr_lenght ,f_sent);
printer(array, arr_lenght);
return 0;
}
int array_word_creator(word *array, FILE *fp)
{
int n,i=0;
fscanf(fp,"%d",&n);
*array= malloc(n*sizeof(word));
while(fscanf(fp,"%s", array[i].word)!=EOF)
{
i++;
}
initialize(array,n);
return n;
}
void initialize(word array[], int max)
{
int i;
for(i=0;i<max;i++)
{
array[i].occurrance=0;
}
}
void comparator(word array[], int max, FILE *fp)
{
char word[MAX];
int i;
while(fscanf(fp,"%s", word)!=EOF)
{
for(i=0;i<max;i++)
{
if(strcmp(word, array[i].word)==0)
{
array[i].occurrance++;
}
}
}
}
void printer(word array[], int max)
{
int i;
for(i=0;i<max;i++)
{
if(array[i].occurrance>0)
{
printf("The word '%s' occurs %d times\n", array[i].word, array[i].occurrance);
}
}
}
And the compiler says me:
C:\Users\Matteo\Google Drive\Programming\C\lab3\es1\main.c|47|error: incompatible types when assigning to type 'word' from type 'void *'|
I just studied memory allocation so i'm having some trouble with it, especially with structures. If possible, plase link me also some good docs about this subject.
thank you!
In main word *array is a pointer to a structure of type word.
You then pass array, which does not point to anything, to the function array_word_creator.
You then try to assign the pointer returned by malloc to where array is pointing, but it doesn't point anywhere yet, and even if it did, it would be pointing to a word (since it is a word *), so it can't store a pointer, hence the compiler error.
If you want to set the array pointer in main to the result of malloc, you have to pass a pointer to the pointer. int array_word_creator(word **array, FILE *fp), then you would call it by doing array_word_creator(&array, .... ), the your *array = malloc will work.
You want this:
...
arr_lenght = array_word_creator(&array, f_words);
...
int array_word_creator(word **array, FILE *fp)
{
int n, i = 0;
fscanf(fp, "%d", &n);
*array = malloc(n * sizeof(word));
while (fscanf(fp, "%19s", (*array)[i].word) != EOF)
{
i++;
}
initialize(*array, n);
return n;
}
I need your help deallocating memory in below program. I tried as you can see in main, but no success. Can not get how to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char name[25];
char street[25];
char citystate[25];
char zip[6];
}student;
typedef student *studinfo;
/*function prototypes*/
void getinfo(student *details[], int *);
int main(void)
{
int count = 0;
student *studptr[49];
getinfo(studptr, &count);/*call getinfo function to get student info*/
/*int i = 0;
for (i; i<count; i++) {
free(studptr[i]->name);
free(studptr[i]->street);
free(studptr[i]->citystate);
free(studptr[i]->zip);
} */
return 0;
}
Below is a function to get the info from the file. I will use this info later on in sort function and in display function to display the results. After that I should deallocate the memory.
void getinfo(student *details[], int *count)
{
char s[100];
studinfo info;
/*Get student information*/
while (gets(s) != NULL) {
info = (studinfo)malloc(sizeof(student));
strcpy(info->name, s);
gets(info->street);
gets(info->citystate);
gets(info->zip);
details[(*count)++] = info; /*Increase the pointer to next position*/
} /* End of while loop*/
} /* End of getinfo */
There are three problems with your code:
You are trying to free components of struct student. Since these component arrays were not allocated with malloc, you cannot free them; you need to free only the struct itself.
You are using gets, which can cause buffer overruns. You should use fgets instead, passing buffer size, and stdin for the FILE* parameter.
You copy s[100] into info->name. This can potentially overrun the buffer, because info->name fits only 25 characters.
Once you fix these issues, your program should run correctly.
It should be:
int i;
for (i = 0; i < count; i++) {
free(studptr[i]);
}
Since you allocated each student as a single block, you free them the same way.
I have been going crazy trying to figure out what is done wrong. I admit I am inexperienced when it comes to C, but I don't know what is wrong. Is the way that I am accessing/using the struct incorrect?
EDIT: I keep getting EXC_BAD_ACCESS in debugger.
#include <stdio.h>
#include <string.h>
#define MAX_STRING 20
#define MAX_PLYR 16
typedef struct {
char pname[MAX_STRING];
int runs;
char *s;
} Team_t;
int
main(void)
{
Team_t *team_data[MAX_PLYR];
int i;
char *p;
char name[MAX_STRING];
FILE *inp;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLYR;) {
while ((fgets(name, MAX_STRING, inp) != NULL));
printf("Name(i): %s\n", name);
strcpy(team_data[i]->pname, name);
i++;
}
fclose(inp);
return(0);
}
Edit: Here's what's changed, still getting Segmentation Error
#include <stdio.h>
#include <string.h>
#define MAX_STRING 20
#define MAX_PLYR 16
typedef struct {
char pname[MAX_STRING];
int runs;
char s;
} Team_t;
int
main(void)
{
Team_t team_data[MAX_PLYR];
char name[MAX_STRING];
int i;
FILE *inp;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLYR; i++) {
((fgets(name, MAX_STRING, inp)));
if (feof(inp)) {
printf("End of stream\n");
i = MAX_PLYR;
}
else {
if (ferror(inp)) {
printf("Error reading from file\n");
}
printf("Name(i): %s\n", name);
strcpy(team_data[i].pname, name);
}
}
fclose(inp);
return(0);
}
You declare team_data but you don't allocate it; therefore it's pointing off into random memory, as are the imaginary contents of the array. You need to actually create the array, something like
Team_t *team_data[MAX_PLYR] = (Team_t**) malloc(MAX_PLYR * sizeof(Team_t *));
Use structs, not pointers (or if you insist using pointers the allocate space for those structs)
Team_t team_data[MAX_PLYR];
fgets(team_data[i].pname, MAX_STRING, inp)
when you write
Team_t *team_data[MAX_PLYR];
you are not allocating any memory for the actual Team_t records, instead you are setting up an array of pointers to records.
If instead you would write
Team_t team_data[MAX_PLYR];
you would have allocated the records. When you then want to copy into the team_data array you write instead
strcpy( team_data[i].name, name );