Shaki
Shaki

Reputation: 29

C: the pointer to pointer issue

Following is my code, I want to use pointer to pointer to store strings.

char **BlankWords(char word[]){
    // take word 'lad' as an example
    // length of it is 3
    // fill in blank: _ad, l_d, la_, _lad, l_ad, la_d, lad_
    // 3 + 4 = 7
    // which means, length of 'lad' + (length of 'lad') + 1
    int strLength = strlen(word);
    char **blank_words = malloc(sizeof(char*) * (2 * strLength + 1));
    assert(blank_words != NULL);
    int i, j, k;
    for (i = 0; i < strLength; i++){
        // allocate memory for each length of the word
        blank_words[i] = calloc(MAX_WORD_LENGTH, sizeof(char));
        assert(blank_words[i] != NULL);
        char temp[MAX_WORD_LENGTH];
        strcpy(temp, word);
        temp[strLength] = '\0';
        temp[i] = '_';
        blank_words[i] = temp;
       // printf("%s\n", blank_words[0]);
    }
    for (j = strLength; j < (2 * strLength + 1); j++){
        // allocate memory for each length of the word
        blank_words[j] = calloc(MAX_WORD_LENGTH, sizeof(char));
        assert(blank_words[j] != NULL);
        char temp[MAX_WORD_LENGTH];
        strcpy(temp, word);
        temp[(strlen(temp) + 1)] = '\0';
        for (k = (strLength - 1); k >= (j - strLength); k--){
            if (k >= 0){
                temp[k + 1] = temp[k];  // in order to insert '_' to the word, then the other letter move back one
            }
        }
        temp[j - strLength] = '_';   // insert '_' to the word
        blank_words[j] = temp;
    }
    return blank_words;
}

Following is the output, each row was overwritten after each loop, but in my opinion, each row cannot be overwritten, and may store a unique string.

blank_words[0]: lab_
blank_words[1]: lab_
blank_words[2]: lab_
blank_words[3]: lab_
blank_words[4]: lab_
blank_words[5]: lab_
blank_words[6]: lab_

I don't know why the previous data gets overwritten after each loop. In my opinion, the output should be:

blank_words[0]: _ab
blank_words[1]: l_b
blank_words[2]: la_
blank_words[3]: _lab
blank_words[4]: l_ab
blank_words[5]: la_b
blank_words[6]: lab_

Upvotes: 0

Views: 80

Answers (1)

Gene
Gene

Reputation: 46960

As others have said, a local buffer disappears when its scope closes. Since the char** array points to buffers of that sort, the result is undefined behavior. You'll need to allocate the result strings with malloc.

Another tip: You can build the second set of strings by just moving the underscore rather than creating each from scratch. This is simpler:

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

void *safe_malloc(size_t n) {
  void *r = malloc(n);
  assert(r);
  return r;
}

char *stralloc(char *s) {
  return strcpy(safe_malloc((strlen(s) + 1) * sizeof(char)), s);
}

char **variations(char *s) {
  int len = strlen(s), rp = 0;
  char **r = safe_malloc((2 * len + 1) * sizeof *r);;
  char buf[len + 2];
  strcpy(buf, s); // Copy in case s is a read-only literal.
  for (int i = 0; i < len; ++i) {
    char t = buf[i];               // Remember the i'th char.
    buf[i] = '_';                  // Overwrite with _.
    r[rp++] = stralloc(buf);       // Capture a copy.
    buf[i] = t;                    // Replace original char.
  }
  buf[0] = '_';                    // Make the 1st char _.
  strcpy(buf + 1, s);              // Copy the rest after.
  r[rp++] = stralloc(buf);         // Capture a copy.
  for (int i = 0; i < len; ++i) {
    buf[i] = buf[i + 1];           // Overwrite _ with following char.
    buf[i + 1] = '_';              // Move the _ up one position.
    r[rp++] = stralloc(buf);       // Capture a copy.
  }
  return r;
}

Upvotes: 1

Related Questions