2

I need some help regarding dynamic allocation of arrays of pointers in C. I am trying to create a program that reads a sentence of words from user input, and stores the words in character array strings. I then want to save the pointers char *word to these words in an array of pointers char **wordArray.

Creating a working method for dynamic allocation for the words was easy enough, and it reads character by character from user input. However, trying to adapt this method for the array of pointers was trickier.

The current function char **varArray is obviously flawed, but my thinking was "while the user has input, get words pointers for the array of pointers". It now effectively loops the first word for every char c.

My question is, how do I implement a second layer (char **varArray()) of dynamic memory allocation of my array of pointers? How can the function detect when to call char *word()?

Feedback for the code, style, or other errors are of course appreciated. My level is intermediate beginner.

/*CREATES AND ALLOCATES DYNAMIC VARIABLE ARRAY*/
#include <stdio.h>
#include <stdlib.h>

char **varArray();
char *word();

char **varArray()
{
  char **tmp=NULL;
  char **wordArray=NULL;
  size_t size=0;
  char c = EOF;
  int words=0;

  while(c) {
    c=getc(stdin);
    if (c == EOF || c == '\n')
      c=0;

    if (size <= words) {
      size+=sizeof(char *);
      tmp = realloc(wordArray,size);

      if(tmp == NULL) {
        free(wordArray);
        wordArray=NULL;
        printf("Memory allocation failed. Aborted.\n");
        break;
      }

      wordArray=tmp;
    }
    words++;
    wordArray[words]= word();
    return wordArray;
  } 

The method for retrieving ONE word:

/*GETS ONE WORD FROM USER INPUT*/
  char *word()
{
  char *word=NULL, *tmp=NULL;
  size_t size=0;
  char c = EOF;
  int letters=0;

  while(c) { //reads character by character
    c=getc(stdin);

    if (c == EOF || c == '\n' || c==' ') //remove ' ' to read all input
      c =0;

    if (size <= letters) { //increase and reallocate memory
      size = size + sizeof(char);
      tmp = realloc(word,size);

      if (tmp==NULL) { //check if allocation failed
        free(word);
        word=NULL;
        printf("Memory allocation failed. Aborted.\n");
        break;
      }
      word= tmp;
    }
    letters=letters+1; 
    word[letters]=c;

  }
  /*ADD SENTINEL CHARACTER*/
  letters++; 
  size += sizeof(char);
  word = realloc(word,size);
  word[letters]='\n';
  return word;
}
11
  • Detail: Looks like code reads a line (character up to a '\n') and not a sentence. Commented Oct 7, 2017 at 19:52
  • Step 1: char c = EOF; --> int c = EOF; Commented Oct 7, 2017 at 19:53
  • Correct, it reads a line, I was trying to convey its purpose: That it reads a line of words, for example a sentence, pragmatically. Commented Oct 7, 2017 at 19:56
  • Note: Good that if(tmp == NULL) looks for allocation failure,yet code will die with wordArray=NULL; ... break; ... wordArray[words]= .... Commented Oct 7, 2017 at 19:56
  • (1) You need to pass the last character (space/tab/new line/EOF) information from word() to varArray(). (2) In varArray(), check the character and if it is not space/tab, break the loop. Otherwise continue. Commented Oct 7, 2017 at 20:05

2 Answers 2

1

Here's the skeleton of the program you want to write.

 ...
     char* currentWord;
     char **wordArray=NULL;
     while ((currentWord = word()) != NULL) {
        .... add current word to word array with realloc...
     }
 ....

 char* word() {
     int ch;
     char* outputWord = NULL;
     while ((ch = getch()) != EOF) {
        if ( ... ch is a word character ... )
             ... add ch to output word with realloc ...
         else {
             char* ret = outputWord;
             outputWord = NULL;
             return ret;
        }
     }
     return NULL;
 }

Note how the two while loops are doing exactly the same thing.

  while ((element = getNextElement()) != sentinelValue) {  
      .... process newly obtained element ....
  }
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, @n.m. I appreciate the conceptual outline. If I understand it correctly, the inner while loop should accumulate word characters until it enounters say a space? I'm a bit stuck in the reasoning of my old code, however. How does the outer loop avoid looping over every character? If it does.
Yes the inner while loop should accumulate word characters like you say. My outer loop doesn't see individual characters, it loops over words. Yours is a bit hard to reason about as it's too convoluted. You probably don't want to continue with it.
0

I have now successfully implemented a version of the shell provided by @n.m. However, another problem arose - since word() relies on the sentinel newline character \n to quit, it also fails to read the final word, and does not enter the loop the last, vital time.

I have tried to implement some if-cases, but these of course fail due to the while-condition. Another idea would be to implement some switch case, but I am not sure that would avoid the nastiness of the while loop?

Do note that the code has little error checking to minimise the clutter.

  char **wordArray() {
  char *currentWord;
  char **wordArray=NULL;
  size_t size=0;
  int i=0;

  while((currentWord = word()) != NULL) {
    size+=sizeof(char *);
    wordArray=(char **) realloc(wordArray,size);
    wordArray[i]=currentWord;
    printf("Test - Current word: %s\n",currentWord);
    i++;

  }
  return wordArray;
}

The relevant word() function:

char *word() {
  char ch;
  int i=0;
  size_t size=0;
  char *returnWord = NULL;
  char *outputWord = NULL;
  char *tmp = NULL;

  while((ch = getc(stdin)) != EOF && ch !='\n') { //&& ch !='\n'
    if (ch != ' ' ) { //&& ch !='\n'
      size += sizeof(char);
      tmp = (char *) realloc(outputWord,size);
        outputWord= tmp;
        outputWord[i]=ch;
        printf("Test1: %c\n",*(outputWord+i));
        i++;
    } else {
        printf("Test2: %s\n",outputWord);
        returnWord=outputWord;
        outputWord=NULL;
        printf("Test3: %s\n",returnWord);
      return returnWord;
    }
  }
  return NULL;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.