A function returning string or pointer

Discussion in 'C Programming' started by svata, Nov 13, 2006.

  1. svata

    svata Guest

    Hello to all,

    as a result from my previous post I'm busy with splitting code into
    functions.
    The one problem ( out of many ) I encounter is how to properly
    use/code a function which returns either array of characters(string) or
    a pointer to this array.

    I read some articles, some other posts and come to this solution:


    char *read_name(void){
    static char item_name[11];
    char *p_item_name;

    printf("Enter the description: ");
    if (fgets(item_name, sizeof(item_name), stdin) != NULL){
    /* if the input contains a new line */
    if (( p_item_name = strchr(item_name, '\n')) != NULL ){
    *p_item_name = '\0'; /* get rid of new line */
    }
    else {
    while(getchar() != '\n'){ /* get rid of the rest in the buffer */
    ;
    }
    }
    }
    return item_name; /* return string in the form of character array */
    }

    Are there other solutions? What are the pros and cons using
    array/pointer?

    svata
    svata, Nov 13, 2006
    #1
    1. Advertising

  2. svata

    Guest

    Hello Svata,

    > as a result from my previous post I'm busy with splitting code into
    > functions.
    > The one problem ( out of many ) I encounter is how to properly
    > use/code a function which returns either array of characters(string) or
    > a pointer to this array.
    >
    > I read some articles, some other posts and come to this solution:


    <snip>

    > Are there other solutions? What are the pros and cons using
    > array/pointer?


    Your code is fine, especially if the item_name read should be truncated
    to 10 characters (this limit could be defined as constant, BTW, to make
    code change easier).

    Cheers,
    Loic.
    , Nov 13, 2006
    #2
    1. Advertising

  3. svata

    Chris Dollin Guest

    svata wrote:

    > Hello to all,
    >
    > as a result from my previous post I'm busy with splitting code into
    > functions.
    > The one problem ( out of many ) I encounter is how to properly
    > use/code a function which returns either array of characters(string) or
    > a pointer to this array.


    You /must not/ return a pointer to an array which is a local
    non-static variable of the function.

    > I read some articles, some other posts and come to this solution:
    >
    > char *read_name(void){
    > static char item_name[11];


    (fx:snip)

    > return item_name; /* return string in the form of character array */
    > }


    So you /must not/ do this. The variable `item_name` evaporates when
    the function returns, so the pointer to it isn't pointing anywhere
    and any use of it gets you undefined behaviour -- which is a Very
    Bad Thing.

    You must return a pointer to store which will outlive the function
    call: for example:

    * a static array, usually a bad idea because different uses of the
    function will share that array.

    * mallocated store (which the using code will have to free)

    * store passed in as an argument (so it's the caller's problem)

    * mix as desired (carefully)

    --
    Chris "hantwig efferko VOOM!" Dollin
    Meaning precedes definition.
    Chris Dollin, Nov 13, 2006
    #3
  4. svata

    Chris Dollin Guest

    wrote:

    > Hello Svata,
    >
    >> as a result from my previous post I'm busy with splitting code into
    >> functions.
    >> The one problem ( out of many ) I encounter is how to properly
    >> use/code a function which returns either array of characters(string) or
    >> a pointer to this array.
    >>
    >> I read some articles, some other posts and come to this solution:

    >
    > <snip>
    >
    >> Are there other solutions? What are the pros and cons using
    >> array/pointer?

    >
    > Your code is fine,


    Not so, as my reply to svata explains.

    --
    Chris "hantwig efferko VOOM!" Dollin
    "People are part of the design. It's dangerous to forget that." /Star Cops/
    Chris Dollin, Nov 13, 2006
    #4
  5. svata

    Chris Dollin Guest

    Chris Dollin, the complete idiot, wrote:

    > svata wrote:
    >
    >> Hello to all,
    >>
    >> as a result from my previous post I'm busy with splitting code into
    >> functions.
    >> The one problem ( out of many ) I encounter is how to properly
    >> use/code a function which returns either array of characters(string) or
    >> a pointer to this array.

    >
    > You /must not/ return a pointer to an array which is a local
    > non-static variable of the function.
    >
    >> I read some articles, some other posts and come to this solution:
    >>
    >> char *read_name(void){
    >> static char item_name[11];

    >
    > (fx:snip)
    >
    >> return item_name; /* return string in the form of character array */
    >> }

    >
    > So you /must not/ do this.


    OK, OK, I'm blind. I read it three times and didn't see `static`.
    As soon as I posted, I saw it.

    Sorry sorry sorry. Egg egg egg. Time to go hone.

    > You must return a pointer to store which will outlive the function
    > call: for example:
    >
    > * a static array, usually a bad idea because different uses of the
    > function will share that array.


    So you were OK to do what you did, except there's a gotcha you
    need to beware of.

    --
    Chris "hantwig efferko VOOM!" Dollin
    "Life is full of mysteries. Consider this one of them." Sinclair, /Babylon 5/
    Chris Dollin, Nov 13, 2006
    #5
  6. "svata" <> wrote in message
    news:...
    > as a result from my previous post I'm busy with splitting code into
    > functions.
    > The one problem ( out of many ) I encounter is how to properly
    > use/code a function which returns either array of characters(string)
    > or
    > a pointer to this array.
    >
    > I read some articles, some other posts and come to this solution:

    ....
    > Are there other solutions? What are the pros and cons using
    > array/pointer?


    Returning a pointer to a static buffer is a common technique. However,
    that has the problem that your callers need to be aware of that, and
    they'll likely need to strdup() the results if they want to call the
    function frequently. It also means the function is not reentrant, which
    can kill you if you try to call that function from multiple threads,
    signal handlers, etc.

    malloc()ing a new buffer for each call is also done at times. That
    solves the above problems, but it means that the caller needs to know to
    free() the strings you return when they're done with them, or they'll
    end up with a memory leak.

    The last common option is to require the caller to provide a buffer (and
    its size!) for you; you just put the string into their buffer. By
    requiring the caller to do the malloc(), it makes it easier for them to
    see they need to do a free(). Or they might use a local array, if they
    know how big to make it.

    The question in all cases is what to do if the buffer isn't big enough
    for the input. If you _know_ that a certain size will never be
    exceeded, you can go with that, but such "knowledge" usually turns out
    to be incorrect after several maintenance/release cycles. You'll need
    to spend as much time figuring out this problem as you are deciding who
    allocates the buffer where.

    S

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking



    --
    Posted via a free Usenet account from http://www.teranews.com
    Stephen Sprunk, Nov 13, 2006
    #6
  7. svata

    goose Guest

    svata wrote:
    > Hello to all,
    >
    > as a result from my previous post I'm busy with splitting code into
    > functions.
    > The one problem ( out of many ) I encounter is how to properly
    > use/code a function which returns either array of characters(string) or
    > a pointer to this array.
    >
    > I read some articles, some other posts and come to this solution:
    >
    >
    > char *read_name(void){
    > static char item_name[11];
    > char *p_item_name;
    >
    > printf("Enter the description: ");
    > if (fgets(item_name, sizeof(item_name), stdin) != NULL){
    > /* if the input contains a new line */
    > if (( p_item_name = strchr(item_name, '\n')) != NULL ){
    > *p_item_name = '\0'; /* get rid of new line */
    > }
    > else {
    > while(getchar() != '\n'){ /* get rid of the rest in the buffer */
    > ;
    > }
    > }
    > }
    > return item_name; /* return string in the form of character array */
    > }
    >
    > Are there other solutions? What are the pros and cons using
    > array/pointer?
    >


    Stephen below suggests the caller supplying the buffer
    (and length). It is sometimes desirable for the caller
    to repeatedly call the function each time receiving as
    much of the data as can fit in the buffer.

    e.g.

    int foo (char *buf, int length)
    {
    /* copy data_to_be_returned into buf, not exceeding length */
    return 0;
    }
    ....
    char buf[20];
    int length = foo (buf, sizeof buf);
    while (length) {
    length = foo (buf, sizeof buf);
    /* Use the data here */
    }

    You can also make the called function behave differently
    depending on the argument supplied, supplying a NULL pointer
    for the buffer would return the length needed (hard to do with
    the above example). This has the disadvantage of seriously
    confusing the reader, so comment clearly in header, etc.

    e.g.

    int foo (char *buf)
    {
    /* process and store data to be returned in a static buffer */
    if (!buf) {
    return length_of_data_to_be_returned;
    } else {
    memcpy (buf, data_to_be_returned, length_of_data_to_be_returned);
    }
    return 0;
    }
    ....
    int length = foo (NULL);
    char *buf = malloc (length);
    if (!buf) {
    /* error!!! */
    } else {
    foo (buf);
    }
    ....
    free (buf);


    Basically, every solution will have pros and cons, and
    it's up to you to choose which is best for the situation.
    There is no "one-good-way" that can be applied to all
    situations; be thankful that you've got such a variety
    of methods available :)

    goose,
    hth
    goose, Nov 13, 2006
    #7
  8. svata

    Eric Sosman Guest

    svata wrote On 11/13/06 09:44,:
    > [...]
    > The one problem ( out of many ) I encounter is how to properly
    > use/code a function which returns either array of characters(string) or
    > a pointer to this array.
    > [...]


    Others have addressed your immediate question. I'd like
    to draw your attention to two other issues:


    > printf("Enter the description: ");
    > if (fgets(item_name, sizeof(item_name), stdin) != NULL){


    Question 12.4 in the comp.lang.c Frequently Asked Questions
    list http://www.c-faq.com/ explains why you'd be well-advised to
    insert fflush(stdout); between these two lines.

    > /* if the input contains a new line */
    > if (( p_item_name = strchr(item_name, '\n')) != NULL ){
    > *p_item_name = '\0'; /* get rid of new line */
    > }
    > else {
    > while(getchar() != '\n'){ /* get rid of the rest in the buffer */
    > ;
    > }


    A good effort, but it overlooks one possibility: What does
    getchar() return at end-of-input (or I/O error)? What will
    this code do if that happens?

    --
    Eric Sosman, Nov 13, 2006
    #8
  9. svata

    Old Wolf Guest

    svata wrote:
    > Hello to all,
    >
    > as a result from my previous post I'm busy with splitting code into
    > functions. The one problem ( out of many ) I encounter is how to
    > properly use/code a function which returns either array of
    > characters(string) or a pointer to this array.


    I prefer making the caller pass in a buffer and a buffer size, and
    then the function fills in the buffer and returns the length filled in.
    (Or returns a status code and passes the length back via a
    pointer parameter, etc.)

    This way, the function is not tied to any particular memory
    management scheme, and can be called from various places in
    your code without having to waste any memory or perform any
    acrobatics.

    It is also common to allow the function to accept NULL as the
    buffer, in which case it will return the size of buffer required, and
    then the caller can allocate space if necessary and call the
    function again.
    Old Wolf, Nov 13, 2006
    #9
  10. "svata" <> writes:
    [...]
    > The one problem ( out of many ) I encounter is how to properly
    > use/code a function which returns either array of characters(string) or

    [...]
    > Are there other solutions? What are the pros and cons using
    > array/pointer?


    See the comp.lang.c FAQ, <http://www.c-faq.com/>, particularly
    questions 7.5a and 7.5b.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Nov 14, 2006
    #10
  11. svata

    svata Guest

    Eric Sosman wrote:

    > A good effort, but it overlooks one possibility: What does
    > getchar() return at end-of-input (or I/O error)? What will
    > this code do if that happens?


    It is EOF, am I right?

    svata
    svata, Nov 14, 2006
    #11
  12. svata

    Eric Sosman Guest

    svata wrote On 11/14/06 05:44,:
    > Eric Sosman wrote:
    >
    >
    >> A good effort, but it overlooks one possibility: What does
    >>getchar() return at end-of-input (or I/O error)? What will
    >>this code do if that happens?

    >
    >
    > It is EOF, am I right?


    Yes, that's what getchar() will return. Now, what
    will your code do if that happens?

    --
    Eric Sosman, Nov 14, 2006
    #12
  13. svata

    svata Guest

    Eric Sosman wrote:

    > Yes, that's what getchar() will return. Now, what
    > will your code do if that happens?


    So, it should look as follows:

    while(getchar() != EOF && getchar() != '\n'){
    ;
    }

    One has to check for EOF as well, I suppose.

    svata
    svata, Nov 14, 2006
    #13
  14. svata

    Chris Dollin Guest

    svata wrote:

    > Eric Sosman wrote:
    >
    >> Yes, that's what getchar() will return. Now, what
    >> will your code do if that happens?

    >
    > So, it should look as follows:
    >
    > while(getchar() != EOF && getchar() != '\n'){
    > ;
    > }
    >
    > One has to check for EOF as well, I suppose.


    You realise that code will test two different characters?
    (Even if they have the same value ...)

    --
    Chris "hantwig efferko VOOM!" Dollin
    Nit-picking is best done among friends.
    Chris Dollin, Nov 14, 2006
    #14
  15. svata

    santosh Guest

    svata wrote:
    > Eric Sosman wrote:
    >
    > > Yes, that's what getchar() will return. Now, what
    > > will your code do if that happens?

    >
    > So, it should look as follows:
    >
    > while(getchar() != EOF && getchar() != '\n'){
    > ;
    > }
    >
    > One has to check for EOF as well, I suppose.


    Don't call getchar() twice. Each call will return a different value.
    Also you're discarding both return values. I think you may find the
    following code snippet more suited to what you were probably trying to
    do.

    int c;
    ....

    while((c = getchar()) != EOF) {
    if(c != '\n') {
    DO_SOMETHING;
    }
    }

    Now a return value of EOF could be caused either by end of file or some
    kind of I/O error. Presumably, you'd consider the former to be a normal
    condition and the latter as an error of some severity. To find which of
    them caused getchar() to return EOF, you might use ferror() and/or
    feof(). The former returns non-zero if the stream has encountered an
    I/O error, while the latter returns true when end of file has been
    reached on the stream. Once you determine that then appropriate action
    can be taken. Use clearerr() to reset the stream's end of file and
    error indicators.
    santosh, Nov 14, 2006
    #15
  16. svata

    CBFalconer Guest

    svata wrote:
    > Eric Sosman wrote:
    >
    >> Yes, that's what getchar() will return. Now, what
    >> will your code do if that happens?

    >
    > So, it should look as follows:
    >
    > while(getchar() != EOF && getchar() != '\n'){
    > }
    >
    > One has to check for EOF as well, I suppose.


    This is agonizing. To put it out of its misery:

    int flushln(FILE *f) {
    int ch;

    while ((EOF != (ch = getc(f)) && (ch != '\n')) continue;
    return ch;
    }

    Replace your code with "someint = flushln(stdin);" and decide what
    needs doing when (and if) someint becomes EOF.

    --
    Chuck F (cbfalconer at maineline dot net)
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net>
    CBFalconer, Nov 14, 2006
    #16
  17. svata

    Simon Biber Guest

    CBFalconer wrote:
    > This is agonizing. To put it out of its misery:
    >
    > int flushln(FILE *f) {
    > int ch;
    >
    > while ((EOF != (ch = getc(f)) && (ch != '\n')) continue;
    > return ch;
    > }


    This is correct code, but tricky code. It's a sufficiently common idiom
    in C programs that I would expect any programmer to be able to
    understand it, along with the even commoner idiom:
    while((ch = getc(fp)) != EOF) { ... }

    That said, however, in my opinion it is best practise to avoid trying to
    put the whole loop contents into the loop condition when it's not needed.

    If one wants to write simple, easy to read C, I think one should adhere
    to the rule that loop bodies are supposed to make changes to program
    state, while (while, for, if) conditions are supposed to make a decision
    based on the current program state but not make changes to that state.

    Here's another way to write it, which is simpler to read in my opinion:

    int flushln(FILE *fp)
    {
    int ch;

    do
    {
    ch = getc(fp);
    }
    while(ch != EOF && ch != '\n');

    return ch;
    }

    --
    Simon.
    Simon Biber, Nov 14, 2006
    #17
  18. svata

    santosh Guest

    Simon Biber wrote:
    > CBFalconer wrote:
    > > This is agonizing. To put it out of its misery:
    > >
    > > int flushln(FILE *f) {
    > > int ch;
    > >
    > > while ((EOF != (ch = getc(f)) && (ch != '\n')) continue;
    > > return ch;
    > > }

    >
    > This is correct code, but tricky code. It's a sufficiently common idiom
    > in C programs that I would expect any programmer to be able to
    > understand it, along with the even commoner idiom:
    > while((ch = getc(fp)) != EOF) { ... }
    >
    > That said, however, in my opinion it is best practise to avoid trying to
    > put the whole loop contents into the loop condition when it's not needed.
    >
    > If one wants to write simple, easy to read C, I think one should adhere
    > to the rule that loop bodies are supposed to make changes to program
    > state, while (while, for, if) conditions are supposed to make a decision
    > based on the current program state but not make changes to that state.
    >
    > Here's another way to write it, which is simpler to read in my opinion:
    >
    > int flushln(FILE *fp)
    > {
    > int ch;
    >
    > do
    > {
    > ch = getc(fp);
    > }
    > while(ch != EOF && ch != '\n');
    >
    > return ch;
    > }


    This may be okay for flushing input but if you want to process it, then
    having the test for EOF and NL at the bottom is wasteful as the code
    within the DO clause has to do the test anyway.
    santosh, Nov 14, 2006
    #18
  19. In article <>,
    santosh <> wrote:

    >> do
    >> {
    >> ch = getc(fp);
    >> }
    >> while(ch != EOF && ch != '\n');


    >This may be okay for flushing input but if you want to process it, then
    >having the test for EOF and NL at the bottom is wasteful as the code
    >within the DO clause has to do the test anyway.


    A reasonable compiler will optimise that if you could. Even if it
    doesn't, clarity is usually much more important than that kind of
    micro-optimisation.

    -- RIchard
    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
    Richard Tobin, Nov 14, 2006
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. glen stark
    Replies:
    2
    Views:
    686
    Ron Natalie
    Oct 10, 2003
  2. Fraser Ross
    Replies:
    4
    Views:
    1,023
    Fraser Ross
    Aug 14, 2004
  3. Protoman
    Replies:
    14
    Views:
    556
    Protoman
    Dec 11, 2005
  4. Mark Piffer
    Replies:
    9
    Views:
    895
    luserXtrog
    May 15, 2009
  5. pembed2012
    Replies:
    1
    Views:
    408
    James Kuyper
    Feb 27, 2012
Loading...

Share This Page