Sedmaister
Sedmaister

Reputation: 585

Best way to create a string in C and pass it down function to function?

I want to create a string and pass it down function to function as it gets modified. I want to achieve this writing minimal code possible. What would be the best way to do this?

The snippet below is my take on this problem. It does compile, however, does not produce the expected result. I have defined the string in the function stringA(). The idea is stringA() will pass down function to function (i.e. stringB(), stringC()...) as it gets modified. condition() would always return 0 and it is just a use case if we need to make a conditional return.

static inline int condition(void)
{
#ifdef SIM
    return 1;
#else
    return 0;
#endif
}

const char *stringA(void)
{
    return condition() ? "." : "/mnt/mmcblk0p1";
}

static inline const char *stringB(void)
{
    char buf[128];
    snprintf(buf, sizeof(buf), "%s/pathB", stringA());
    return condition() ? "" : buf;
}

void main()
{
      /* Pass 1 */
      char *str1 = strdup(stringB());
      printf("%s\n", str1); 

      /* Pass 2 */
      char *str2 = stringB();
      printf("%s\n", str2);

      /* Pass 3 */
      char str3[256];
      strcpy(str3, stringB());

      return;
}

Further questions and feedbacks:

1) Pass 1 does not print anything. Why?

2) Pass 2 does not print anything. Again why? I thought using strdup() would pass all the char pointers to str2.

3) Pass 3 printed garbage (unwanted chars). Why? I chose not to use pointer. strcpy() did not seem to work.

4) I removed the condition() from the return statement and I got a seg fault. Why?

static inline const char *stringB(void)
{
    char buf[128];
    snprintf(buf, sizeof(buf), "%s/pathB", stringA());
    return buf;
}

5) However, this approach below (I used arguments) seemed to print out "/mnt/mmcblk0p1/pathB" just fine. I am not sure how that worked when my other attempts failed. Any explanation? I am not particularly a big fan of this approach as it requires me to create needless arguments and create a needless *buf variable in main()

static inline const char *stringB(char *buf, int len)
{
    snprintf(buf, len, "%s/pathB", stringA());
    return condition() ? "" : buf;
}

void main()
{
      char *buf;
      char *str1 = strdup(stringB(buf, 128));
      printf("%s\n", str1); //It prints 
      return;
}

Upvotes: 1

Views: 72

Answers (2)

Grady Player
Grady Player

Reputation: 14549

static inline const char *stringB(void)
{
    char buf[128];
    snprintf(buf, sizeof(buf), "%s/pathB", stringA());
    return condition() ? "" : buf;
}

basically you dont want to ever do this.... returning the buf here, is returning memory that is just on the stack and will be re-used by something else... maybe the calling function... at any rate it isn't your memory... you can return "" that is a static char * and can't change... if you want to return a string it will have to either be in a buffer that is passed into the function like:

static inline const char *stringB(char *buf, size_t len)
{
    snprintf(buf, len, "%s/pathB", stringA());
    return condition() ? "" : buf;
}

returning the buffer you just passed in doesn't make the most sense... but it is legal...

or malloced in the function;

static inline const char *stringB(void)
{
    char * buf = malloc(128);
    snprintf(buf, 128, "%s/pathB", stringA());
    return condition() ? "" : buf;
}

Upvotes: 1

Stephan Lechner
Stephan Lechner

Reputation: 35154

With...

static inline const char *stringB(void)
{
    char buf[128];
    ...
    return buf;
}

you are returning a pointer to a local variable, which's lifetime ends once the function stringB is left. Accessing this pointer then is undefined behaviour, and what you are observing is just that.

Just to try it out, write static char buf[128];, such that the buffer's lifetime exceeds that of the function execution. This is, however, not the best solution as it is not thread safe. Passing the destination to the function as you do with stringB(char *buf, int len) is better (though you should return buf in all code paths then).

Upvotes: 0

Related Questions