[Solved] returning string in C function [closed]


The idea is not that bad, the main errors are the mix-up of numerical digits and characters as shown in the comments.

Also: if you use dynamic memory, than use dynamic memory. If you only want to use a fixed small amount you should use the stack instead, e.g.: c[100], but that came up in the comments, too. You also need only one piece of memory. Here is a working example based on your code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ALL CHECKS OMMITTED!
char *countAndSay(int A)
{
  int k, count, j;
  // "i" gets compared against the output of
  // strlen() which is of type size_t
  size_t i;
  char a;

  // Seed needs two bytes of memory 
  char *c = malloc(2);
  // Another pointer, pointing to the same memory later.
  // Set to NULL to avoid an extra malloc()
  char *temp = NULL;
  // a temporary pointer needed for realloc()-ing
  char *cp;
  // fill c with seed
  c[0] = '1';
  c[1] = '\0';
  if (A == 1) {
    return c;
  }
  // assuming 1-based input, that is: the first 
  // entry of the sequence is numbered 1 (one)
  for (k = 2; k <= A; k++) {
    // Memory needed is twice the size of
    // the former entry at most.
    // (Averages to Conway's constant but that
    // number is not usable here, it is only a limit)
    cp = realloc(temp, strlen(c) * 2 + 1);
    temp = cp;
    for (i = 0, j = 0; i < strlen(c); i++) {
      //printf("A i = %zu, j = %zu\n",i,j);
      a = c[i];
      count = 1;
      i++;
      while (c[i] != '\0') {
        if (c[i] == a) {
          count++;
          i++;
        } else {
          i--;
          break;
        }
      }
      temp[j++] = count + '0';
      temp[j++] = a;
      //printf("B i = %zu, j = %zu\n",i,j-1)
      //printf("B i = %zu, j = %zu\n",i,j);
    }
    temp[j] = '\0';
    if (k < A) {
      // Just point "c" to the new sequence in "temp".
      // Why does this work and temp doesn't overwrite c later?
      // Or does it *not* always work and fails at one point?
      // A mystery! Try to find it out! Some hints in the code.
      c = temp;
      temp = NULL;
    }
    // intermediate results:
    //printf("%s\n\n",c);
  }
  return temp;
}

int main(int argc, char **argv)
{
  // your code goes here
  char *c = countAndSay(atoi(argv[1]));
  printf("%s\n", c);
  free(c);
  return 0;
}

To get a way to check for sequences not in the list over at OEIS, I rummaged around in my attic and found this little “gem”:

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

char *conway(char *s)
{
  char *seq;
  char c;
  size_t len, count, i = 0;

  len = strlen(s);
  /*
   * Worst case is twice as large as the input, e.g.:
   * 1 -> 11
   * 21 -> 1211
   */
  seq = malloc(len * 2 + 1);
  if (seq == NULL) {
    return NULL;
  }
  while (len) {
    // counter for occurrences of ...
    count = 0;
    // ... this character
    c = s[0];
    // as long as the string "s" 
    while (*s != '\0' && *s == c) {
      // move pointer to next character
      s++;
      // increment counter
      count++;
      // decrement the length of the string
      len--;
    }
    // to keep it simple, fail if c > 9
    // but that cannot happen with a seed of 1
    // which is used here.
    // For other seeds it might be necessary to
    // use a map with the higher digits as characters.
    // If it is not possible to fit it into a
    // character, the approach with a C-string is
    // obviously not reasonable anymore.
    if (count > 9) {
      free(seq);
      return NULL;
    }
    // append counter as a character
    seq[i++] = (char) (count + '0');
    // append character "c" from above
    seq[i++] = c;
  }
  // return a proper C-string
  seq[i] = '\0';
  return seq;
}


int main(int argc, char **argv)
{
  long i, n;
  char *seq0, *seq1;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s n>0\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  // reset errno, just in case
  errno = 0;
  // get amount from commandline
  n = strtol(argv[1], NULL, 0);
  if ((errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))
      || (errno != 0 && n == 0)) {
    fprintf(stderr, "strtol failed: %s\n", strerror(errno));
    exit(EXIT_FAILURE);
  }

  if (n <= 0) {
    fprintf(stderr, "Usage: %s n>0\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  // allocate space for seed value "1" plus '\0'
  // If the seed is changed the limit in the conway() function
  // above might need a change.
  seq0 = malloc(2);
  if (seq0 == NULL) {
    fprintf(stderr, "malloc() failed to allocate a measly 2 bytes!?\n");
    exit(EXIT_FAILURE);
  }
  // put the initial value into the freshly allocated memory 
  strcpy(seq0, "1");
  // print it, nicely formatted
  /*
   * putc('1', stdout);
   * if (n == 1) {
   * putc('\n', stdout);
   * free(seq0);
   * exit(EXIT_SUCCESS);
   * } else {
   * printf(", ");
   * }
   */
  if (n == 1) {
    puts("1");
    free(seq0);
    exit(EXIT_SUCCESS);
  }
  // adjust count
  n--;
  for (i = 0; i < n; i++) {
    // compute conway sequence as a recursion
    seq1 = conway(seq0);
    if (seq1 == NULL) {
      fprintf(stderr, "conway() failed, probably because malloc() failed\n");
      exit(EXIT_FAILURE);
    }
    // make room
    free(seq0);
    seq0 = NULL;
    // print sequence, comma separated
    // printf("%s%s", seq1, (i < n - 1) ? "," : "\n");
    // or print sequence and length of sequence, line separated
    // printf("%zu: %s%s", strlen(seq1), seq1, (i < n-1) ? "\n\n" : "\n");
    // print the endresult only
    if (i == n - 1) {
      printf("%s\n", seq1);
    }
    // reuse seq0
    seq0 = seq1;
    // not necessary but deemed good style by some
    // although frowned upon by others
    seq1 = NULL;
  }
  // free the last memory
  free(seq0);
  exit(EXIT_SUCCESS);
}

solved returning string in C function [closed]