1

I wrote a substr function in c, I can get the returned value inside the substr function, but can not get the returned value in main function. Below is all the code:

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

char* substr(char *source, int start, int length)
{
    char result[10];
    char *r = result;
    strncpy(result, source+start, length);
    printf("substr: %s\n", r);
    return r;
}

int main()
{
    printf("main: %s\n", substr("HELLO", 1, 2));
}

and the output is:

substr: EL
main: 

I'm not familiar with c, anybody get the idea to fix this, thanks in advance.

ecco
  • 506
  • 1
  • 4
  • 6
  • possible duplicate of [Returned string value becomes garbage](http://stackoverflow.com/questions/15020105/returned-string-value-becomes-garbage) – alk Feb 25 '13 at 05:58

4 Answers4

4

result only exists during the call to your substr. Your main is referencing bad memory.

you could fix it by:

  • making result static in substr.
  • dynamically allocating result (remember to free)
  • making result global

As cthulhu ( "Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn" ) points out: even if you applied one of my fixes: your string isn't nul terminated.

Also since you have a fixed size result buffer, you could cause problems by asking for a substring longer than 10 - either check your arguments, or don't use a fixed size buffer.

I haven't tested this, so there may well be an "off by one" problem or two lurking in the corners...

/* 
 * Caller must free the results if they are non null 
 */
char* substr(char *source, int start, int length)
{
    /* If the input is NULL, return NULL */
    if (source == NULL) return NULL;

    int len = strlen(source);

    /* If the requested start is off the end of the string, return NULL */
    if (start > len) return NULL;

    /* If the requested length is 0 or less, return NULL */ 
    if (length <= 0) return 0;

    char *r = (char*)malloc(length + 1); /* allow space for null terminator */
    if (r != NULL) {
        int i = 0;
        while(source[start] != '\0' && i < length) {
            r[i++] = source[start++];
        }
        r[i] = '\0';
        printf("substr: %s\n", r);
    }
    return r;
}
John3136
  • 28,809
  • 4
  • 51
  • 69
0

If you're going to be expecting to return a value to the caller then you should pass the place where the string will be stored to the function. Standard library functions like strcpy do this. Here is a very simple example. It assumes dest is already declared and is big enough to store it.

char * substr(char * dest, char * src, int start, int length)
{
    //  Move substring into passed destination pointer
    strncpy(dest, src + start, length);

    //  Append null to the end to terminate string
    dest[length] = 0;

    //  Return string pointer that can be used in printf and other places
    return dest;
}

int main(int argc, char const *argv[])
{
    char * test = "This is a test.";
    char * dest = malloc(10);
    printf("%s", substr(dest, test, 5, 2));
    free(dest);
    return 0;
}

Output: is

Edit: To all the people returning values that are malloc'd inside the function, how do you expect people to free the memory if they just use it in a print statement? They receive no pointer to free and the memory will just be left hanging there.

ozdrgnaDiies
  • 1,909
  • 1
  • 19
  • 34
0

The below code allocate memory on the heap. Just free your memory when you are done. strlcpy always NUL-terminate its strings as others have pointed out.

#include <string.h>


char *
substr(char *s, int start, int len)
{
    char *ss;

    if(strlen(s) < start + len)
        return NULL;
    if((ss = malloc(len + 1)) == NULL)
        return NULL;
    strlcpy(ss, s + start, len);
    return ss;
}

int
main(void)
{
    char *s = substr("Hello World!", 6, 5);
    printf("%s\n", s);
    free(s);
    return 0;
}

Should print World.

To use strlcpy in Debian Linux use:

gcc -lcext -o prog prog.c

If your operating system doesn't provide strlcpy just include it yourself in your source. It is licensed under the BSD license, that means free to use, sell, etc, as long you include the license itself.

The implementation of strlcpy can be found on OpenBSD's CVS Web.

emil
  • 1,642
  • 13
  • 12
  • strlcpy isn't in the standard. As far as I'm aware, there isn't a Windows port of this as it doesn't compile in gcc under Windows. This isn't an optimal solution for cross-platform code or straight printing. – ozdrgnaDiies Feb 25 '13 at 05:55
  • @ozdrgnaDiies Thank you for your comment, I have updated my answer accordingly. – emil Feb 25 '13 at 07:17
-1

Dynamic and Static Variables in C

Variable declarations can be outside all functions or inside a function Declarations outside all functions are global and in fixed memory locations The static declaration declares a variable outside a function to be a “file global” (cannot be referenced by code in other source files) Declarations within a block statement {} (function body or block statement nested within a function body): Are dynamically allocated, unless declared static Are allocated memory when program execution enters the block Memory is released when execution exits the block If a function calls itself (directly or indirectly), it gets a new set of dynamic variables (called a stack frame) This is handled no differently from any other call to the function

You have problem, the variable result[] is a variable that has been allocated in side the function — whose lifetime extends across the entire run of the function(allocated at the stack!) because of that you need to make the result Dynamic variable

Fix code:

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

char* substr(char *source, int start, int length)
{
    char* result;
    char *r;
    result=(char*)malloc(sizeof(char)*10);
    r = result;
    strncpy(result, source+start, length);
    printf("substr: %s\n", r);
    return r;
}

int main()
{
    char* r=substr("HELLO", 1, 2);
    printf("main: %s\n",r );
    free(r)//Don't forget to free it!
}

OR you can make result[] global variable like this:

#include <stdio.h>
#include <string.h>
char result[10];//<======Global
char* substr(char *source, int start, int length)
{
    char *r=result;
    r = result;
    strncpy(result, source+start, length);
    printf("substr: %s\n", r);
    return r;
}

int main()
{
    printf("main: %s\n",substr("HELLO", 1, 2));
}
One Man Crew
  • 9,420
  • 2
  • 42
  • 51