0

I am attempting to create a spell checking program that reads in a file containing ~3000 unordered 3-4 letter words which are on a line each, sorts them into alphabetical order and then prints them out.

I have a working version using "standard" array form, array[][], however I'm attempting to modify the program to use pointers only. I thought that by mallocing the array according to the size of char * the size of my file there would be enough memory for the program to execute correctly, however I keep getting SEGV when I run my code, pointing to my while loop.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bubbleSortWordsArray(char **array, int wordCount, int arrSize);
void printWordsArray(char **array, int wordCount);
int numOfLines(FILE *filePoint);

int main(int argc, char **argv) {
   FILE *fp = fopen(argv[1], "r");
   int i = 0, size = numOfLines(fp);
   char **words = (char **)malloc(sizeof(char) * size);

   if (fp == NULL) {
      fprintf(stderr, "fopen failed");
      exit(EXIT_FAILURE);
   }
   while (fgets(words[i], size, fp)) {
      words[i][strlen(words[i]) - 1] = '\0';
      i++;
   }
   
   fclose(fp);

   bubbleSortWordsArray(words, i, size);
   printWordsArray(words, i);

   free(words);
   return (0);
}

void bubbleSortWordsArray(char **array, int wordCount, int arrSize)
{
   int c;
   int d;
   char *swap = (char *)malloc(sizeof(char) * arrSize);

   for (c = 0; c < (wordCount - 1); c++) {
      for (d = 0; d < (wordCount - c - 1); d++) {
         if (0 > strcmp(array[d], array[d + 1])) {
            strcpy(swap, array[d]);
            strcpy(array[d], array[d + 1]);
            strcpy(array[d + 1], swap);
         }
      }
   }
}

void printWordsArray(char **array, int wordCount)
{
   int i;

   printf("\n");
   for (i = 0; i < wordCount; i++) {
      printf("%s\n", array[i]);
   }
}

int numOfLines(FILE *filePoint) {
  int c, count;
  count = 0;
  for (;; ) {
    c = fgetc(filePoint);
    if (c == EOF)
      break;

    if (c == '\n')
      ++count;
  }
  rewind(filePoint);

  return count+1;
}
Davospike
  • 91
  • 1
  • 9
  • 1
    You want `size` pointers but you only allocate `size` characters. And you do never malloc any memory for `words[i]`. Also: You might add 1 to `numOfLines` just in case the last line does not end with `\n`. – Gerhardh Nov 15 '20 at 20:39

2 Answers2

1
char **words = (char **)malloc(sizeof(char) * size);

First, skip the cast and use the variable instead of type. This way you would have avoided the bug you created by using char instead of char*. Read more about it here: https://stackoverflow.com/a/605858/6699433

char **words = malloc(sizeof(*words) * size);

Second. All you have done here is to allocate space for some pointers, but the pointers does not point anywhere. You need something like this afterwards:

for(int i=0; i<size; i++) 
    words[i] = malloc(sizeof (*words[0]) * maxwordsize);

Where maxwordsize needs to be defined somewhere. It may vary for each pointer.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • I've edited my code to mirror your suggestion, placing your for loop directly underneath my variable initialisation. However now I am getting a heap-buffer-overflow with the "Summary" in my terminal pointing to my while loop. – Davospike Nov 15 '20 at 21:09
  • @Davospike Then you need to do some debugging. I also recommend starting with something easier if this is the first time you're working with pointers for real. I just pointed out the most obvious flaw. One thing that MIGHT be the cause of buffer overflow is that `maxwordsize` needs space for the zero terminator. – klutt Nov 15 '20 at 21:11
0

Try something like this:

char **words = (char **)malloc(sizeof(char*) * size);
for(i = 0; i < size; i++){
    words[i] = (char*)malloc(sizeof(char) * (someValue + 2));
}

Where someValue would be the maximum length of your words (make it 4 if you have only 3-4 letter words). Add 2 to this someValue so you also store the '\n' and '\0' signalling the end of each word. Every word will be a new string.

  • 1
    If there are 3-4 letter words in each line, `words[i]` must at least provide space for 6 bytes. 4 Characters + `'\n'` +`0` – Gerhardh Nov 15 '20 at 22:42