By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,703 Members | 1,116 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,703 IT Pros & Developers. It's quick & easy.

return a string

P: n/a
Hello,

How to I do to return a string as a result of a function.
I wrote the following function:

char prt_tralha(int num)
{
int i;
char tralha[num];

tralha = "#";
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));

return tralha;
}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));

return 0;
}

But when I compile it, gcc shows this message:

tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
tmp.c:20: warning: return makes integer from pointer without a cast
tmp.c:20: warning: function returns address of local variable

Thanks,

Nascimento
Nov 14 '05 #1
Share this Question
Share on Google+
23 Replies


P: n/a
Nascimento wrote:
Hello,

How to I do to return a string as a result of a function.
I wrote the following function:

char prt_tralha(int num)
{
int i;
char tralha[num];

tralha = "#";
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));

return tralha;
}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));

return 0;
}

But when I compile it, gcc shows this message:

tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
tmp.c:20: warning: return makes integer from pointer without a cast
tmp.c:20: warning: function returns address of local variable

Thanks,

Nascimento


#include <stdio.h>
#include <stdlib.h>
const char * string_function(void)
{
static const char * my_text = "My text";
return my_text;
}

int main(void)
{
printf("%s\n", string_function());
return EXIT_SUCCESS;
}

Fundamentally, you pass a pointer to a string; not
the string.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book
http://www.sgi.com/tech/stl -- Standard Template Library
Nov 14 '05 #2

P: n/a

Nascimento wrote:
Hello,

How to I do to return a string as a result of a function.
I wrote the following function:

There are two ways to "return" a string from a function. One is to
simply return it...
char prt_tralha(int num)
I.E. char * ptr_tralha(int num)

Here we return a pointer to char, or string. The problem with this is
the return value can't be an automatic variable, so you'll need to work
with malloc.

Another method is to make the string part of the argument list. This is
probably prefered, since the memory management takes place outside of
the function and is (arguably) easier.

I.E. char ptr_tralha(int num, char *ret)
{
int i;
char tralha[num];
Assuming the later method, tralha would simply be the argument to this
function, and not declared here.

tralha = "#";
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));

return tralha;
There would be no need to "return" tralha here, since it was passed in
via pointer in the argument list.
}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));
try this instead:

char tralha[5];
ptr_tralha(5,tralha);
printf("%s \n", tralha);

return 0;
}

But when I compile it, gcc shows this message:

tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
Well, of course. The function is (was) returning a char, but you were
trying to use it as if it were a char *.
tmp.c:20: warning: return makes integer from pointer without a cast
tmp.c:20: warning: function returns address of local variable

Thanks,
Hope this helps. I'm sure others will have suggestions as well.

-Jason
Nascimento


Nov 14 '05 #3

P: n/a
Nascimento,
you cannot assign a char to a string like that:
tralha = "#"
you can do it like this: tralha[0]='#';
A more elegant code for your purpose goes like this:

--- tralha.c ---

void
ptr_tralha(char *s)
{
while (*s != '\0') /* while the contents of s are different
* from NULL */
*s++ = '#'; /* s = '#' . increment s */
}
int
main(void)
{
char s[5];
ptr_tralha(s);
puts(s);

return 0;
}

Nov 14 '05 #4

P: n/a

Nascimento wrote:
int i;
char tralha[num];

tralha = "#";
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));


Oh, no! Look what's happening here! You are trying to copy chars into
the tralha[] array without using the proper notation. This is bad.

What you want to do is use array substript notation or pointer
arithmetic. Substript is by far easier for the beginner.

tralha[0] = '#'; /* Use single quotes for char */
for( i = 1; i < num-1; i++ ) /* i=1, not 0 (see above) */
tralha[i] = '#'; /* again, copy a char only */
tralha[i] = '\0'; /* don't forget the terminator! */

You don't need (or want) strcpy or strcat when you are building an
array from scratch.

Nov 14 '05 #5

P: n/a
un************@gmail.com (Nascimento) writes:
How to I do to return a string as a result of a function.
I wrote the following function:

char prt_tralha(int num)
{
int i;
char tralha[num];

tralha = "#";
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));

return tralha;
}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));

return 0;
}

But when I compile it, gcc shows this message:

tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
tmp.c:20: warning: return makes integer from pointer without a cast
tmp.c:20: warning: function returns address of local variable
All three error messages are correct.

tralha = "#";
error: incompatible types in assignment

You can't assign strings like that. The name of a string variable (or
of any array) is implicitly converted, in most contexts, to a pointer
to its first element. See section 6 of the C FAQ,
<http://www.eskimo.com/~scs/C-faq/top.html>. You can initialize a
char array with a string literal, but I don't think that's what you
want in this case.

return tralha;
warning: return makes integer from pointer without a cast
warning: function returns address of local variable

You declared your function to return a char (a single character
value). You're trying to return a char*. The types are incompatible.
(The "integer" in the first warning refers to type char, which is an
integer type.)

Even if prt_tralha() were declared to return a char*, returning the
address of a local variable would be invalid. Your array tralha
ceases to exist as soon as the function terminates. Your main program
would receive a pointer to a non-existent object, and any attempt to
use it will invoke undefined behavior. In the worst case, it will
work as expected, failing only at the most inconvenient possible
moment. (The compiler isn't required to diagnose this error, but gcc
is kind enough to do so anyway.)

Other problems:

Your declaration "char tralha[num];" declares a variable length array
(VLA). This is a new feature in C99. If you're not concerned about
portability to compilers that don't support VLAs, that's fine, but you
should be aware that such support is not (yet?) universal. You might
consider using malloc() to allocate the memory dynamically.
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));


What is the purpose of the strcpy()? strcat() appends "#" to your
string (assuming tralha is a valid string in the first place) and
returns a pointer to its first element. The strcpy() copies the
nstring onto itself. That's either undefined behavior or a no-op, I
don't remember which.

What you're trying to do is set tralha to a string of num '#'
characters. Using strcat() for this is wasteful.

for (i = 0; i < num; i ++) {
tralha[i] = '#';
}
tralha[num] = '\0';

or

memset(tralha, '#', num);
tralha[num] = '\0';

And since you need space for the trailing '\0', the size of tralha had
better be at least num+1.

Since C doesn't treat arrays as first-class objects (you can't assign
them, compare them, or pass them as parameters, at least not
directly), dealing with character strings can be tricky, especially
when you don't know until execution time how big they're going to be.

If you want a function to return a variable-sized string (or any
array) to its caller, there are basically 3 ways to do it.

1. Let the caller allocate the array. The caller then needs to pass
in the address of the array and its size (and you need to decide what
to do if the caller's array isn't big enough). See the standard
fgets() function for an example.

2. Return a pointer to a static variable. Since static variables
continue to exist after the function returns, this avoids the problem
you had. The drawback is that there's only one allocated result; if
you call your function multiple times, each call will clobber the
previous result. This is especially bad in the presence of recursion
<OT>or multi-threading</OT>.

3. Allocate the result array in the function using malloc(). This is
probably the most flexible method, but it then require the caller to
free() the array when it's finished with it.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 14 '05 #6

P: n/a


Nascimento wrote:
Hello,

How to I do to return a string as a result of a function.
I wrote the following function:

char prt_tralha(int num)
{
int i;
char tralha[num];

tralha = "#";
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));

return tralha;
}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));

return 0;
}

But when I compile it, gcc shows this message:

tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
tmp.c:20: warning: return makes integer from pointer without a cast
tmp.c:20: warning: function returns address of local variable


You seem to be confused about several points. The
comp.lang.c Frequently Asked Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html

covers some of them: Section 6 will help you understand
gcc's first complaint, Question 8.1 explains the second,
and Question 7.5 covers the third.

However, gcc did not catch all your errors. One that
it didn't catch is the strcpy() call: you are passing it
two strings that overlap, but strcpy() requires the source
and destination areas to be distinct. When you try to use
strcpy() on overlapping strings, anything at all might
happen. (Since the overlap is "perfect" -- the source and
destination are exactly the same string -- the strcpy()
call is pointless anyhow. I think this goes back to your
misunderstandings about strings; see FAQ section 8.)

Read the FAQ, re-read your textbook, and start over.
Good luck!

--
Er*********@sun.com

Nov 14 '05 #7

P: n/a
On 29 Apr 2005 14:04:10 -0700, un************@gmail.com (Nascimento)
wrote:
Hello,

How to I do to return a string as a result of a function.
I wrote the following function:

char prt_tralha(int num)
Here, you're saying to return a character, not a string. You want
char * prt_tralha(int num)
where the returned value will be a pointer to a character array
(string).
{
int i;
char tralha[num];
You can't declare a variable size array. What you can do is
char *tralha;
tralha = malloc(num);
but remember to check the return value to make sure the malloc
succeeded. One possibility is
if (tralha == NULL)
return NULL;
Also, since you are allocating new memory, it needs to be freed at
some point. More below on this.
tralha = "#";
You can't just assign strings. (Your first compiler error below.) You
can do
strcpy(tralha, "#");
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));
This makes little sense, but I think I can guess what you're trying to
do. Make a string with num '#'s, right? How about
for( i = 0; i < num-1; i++ )
strcat(tralha, "#");
return tralha;
This is OK now, since you've allocated new memory for tralha. In your
original, you returned the address of a local array, which will be
invalid as soon as you return from the function. This is why you got
the third compiler error. The second error was because you were
returning a pointer, when you told the compiler you wanted to return a
char.}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));
Now, we have the problem that prt_tralha has allocated memory which
needs to be freed. In your test program it doesn't matter, but in a
real program, every call to prt_tralha would allocate more memory, and
you could eventually run out. That's what we call a memory leak. One
way to fix this is

char *temp = prt_tralha(5);
if (temp != NULL)
{
printf("%s \n", temp);
free temp;
}
return 0;
}

But when I compile it, gcc shows this message:
Some hints: Look up the definitions and try to find example uses of
every library function you use, such as strcpy, strcat, malloc, free
above. I referred to all your compiler diagnostics as "errors" on
purpose. Unless you know exactly why the compiler issued a warning,
and you know for certain that it's harmless, consider it an error and
fix it. There is hardly ever a good reason for ignoring compiler
warnings.

Get a good tutorial. I recommend "The C Programming Language" by
Kernighan and Ritchie, which is a good tutorial and reference.
tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
tmp.c:20: warning: return makes integer from pointer without a cast
tmp.c:20: warning: function returns address of local variable

Thanks,

Nascimento


--
Al Balmer
Balmer Consulting
re************************@att.net
Nov 14 '05 #8

P: n/a
mu********@yahoo.com-dot-br.no-spam.invalid (iru_muzgo) writes:
Nascimento,
you cannot assign a char to a string like that:
tralha = "#"
you can do it like this: tralha[0]='#';
A more elegant code for your purpose goes like this:

--- tralha.c ---

void
ptr_tralha(char *s)
{
while (*s != '\0') /* while the contents of s are different
* from NULL */
No. NULL is (a macro that expands to) a null *pointer* constant.
'\0' is a null character, sometimes referred to as NUL. Using the
term NULL to refer to a character value is misleading.
*s++ = '#'; /* s = '#' . increment s */
}
int
main(void)
{
char s[5];
ptr_tralha(s);
puts(s);

return 0;
}


Your array s is not initialized before you pass its address to
ptr_tralha(). Inside ptr_tralha(), you loop over the array until you
find a '\0' character, but there's no reason to assume that you ever
will. Unless there happens to be a '\0' character somewhere within s,
the loop in ptr_tralha() will go past the end of the array, invoking
undefined behavior.

I just tried compiling and running your program, and it printed a
string of 5 '#' characters followed by a newline. Apparently there
just happened to be no '\0' characters in s itself, but there just
happened to be a '\0' character immediately following it in memory.
This is just one of the infinitely many possible consequences of
undefined behavior.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 14 '05 #9

P: n/a
Alan Balmer <al******@att.net> writes:
On 29 Apr 2005 14:04:10 -0700, un************@gmail.com (Nascimento)
wrote:

[...]
{
int i;
char tralha[num];


You can't declare a variable size array.


Yes you can, if you have a C99 compiler or a pre-C99 compiler that
supports the feature. (The form of the diagnostics implies that he's
probably using gcc, which does support VLAs.)

I covered the portability issues in my previous followup.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 14 '05 #10

P: n/a
Nascimento wrote on 29/04/05 :
How to I do to return a string as a result of a function.
I wrote the following function:

char prt_tralha(int num)
{
int i;
char tralha[num];

tralha = "#";
This is not going to happen. You can't change the value of an array
that way. You want strcpy().
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));
Note that this is dangerous. The order of execution of the parameters
is defined by the implementation. BTW, chances are that strcat() is
called before strcpy(). Additionally, strcpy() only works with non
overlapping strings. Your construction doesn't guarantee that.

(To the gurus : [C99] shouldn't the 'restrict' keyword used here by the
compiler to generate some warning ?)

As a rule of thumb, don't use functions as a parameter to another
function. In mosts cases, it hurts...

Finally, it seems to be a very complicated way of filling a string...

return tralha;
Returning the address of a local variable is, in most cases, a
nonsense.
}

And I really like to use it, thus:

int main()
{
printf("%s \n", prt_tralha(5));

return 0;
}

But when I compile it, gcc shows this message:

tmp.c: In function `prt_tralha':
tmp.c:16: error: incompatible types in assignment
Ok, see above.
tmp.c:20: warning: return makes integer from pointer without a cast
Ok, I missed this one. Your function returns a char. You probably want
a char *.
tmp.c:20: warning: function returns address of local variable


A common newbie error. The fact is that the last warning *is* the
point. The address returned by a function must be valid after the
function has terminated. Keep in mind that the duration of the local
variables is limited to the bloc where it was defined. Meaning that
outside of the bloc, it doesn't longer exist. Hence, its address is no
longer valid. Returning its address is technically possible (say for
debug purpose), but dereferencing it out of the function invokes an
undefined behaviour.

There are 3 ways to correct your code.

- The worst : qualifying the array of char with 'static'. This
deceiving solution looks simple and easy, but it can generate other
more subtle bugs preventing from using the function in some cases
(nested calls, mutual calls, recursion, preemptive threads etc.)

- Passing the address of an array. The caller is the game master. He
defines the array, and ask the function to act on it through (address,
size) parameters. (see fgets() for example)

- The function is allocating the array. The caller gives enough
information so that the function is able to compute the requested size
for the array. That done, it allocates the array (malloc()), process
it, and returns its address. The duration of the allocated bloc is
under the control of the program. It ends with an appropriate free().

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++

Nov 14 '05 #11

P: n/a
iru_muzgo wrote on 29/04/05 :
void
ptr_tralha(char *s)
{
while (*s != '\0') /* while the contents of s are different
* from NULL */
NULL is off-topic here. You meant 0. The probel, is what makes you
think that there is a 0 in the area pointed by s ? And even if ther is
one, what makes you think that it is at the right position ?

This is a serious design problem...
*s++ = '#'; /* s = '#' . increment s */
}

int
main(void)
{
char s[5];
As you can see, the contain of is undetermined.
ptr_tralha(s);
hence, the behaviour is undefined. Anything could happen...
puts(s);
return 0;
}


--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.

Nov 14 '05 #12

P: n/a
(supersedes <mn***********************@YOURBRAnoos.fr>)

iru_muzgo wrote on 29/04/05 :
void
ptr_tralha(char *s)
{
while (*s != '\0') /* while the contents of s are different
* from NULL */
NULL is off-topic here. You meant 0. The probem is, what makes you
think that there is a 0 in the area pointed by s ? And even if there is
one, what makes you think that it is at the correct position ?

This is a serious design problem...
*s++ = '#'; /* s = '#' . increment s */
}

int
main(void)
{
char s[5];
As you can see, the contain of is undetermined.
ptr_tralha(s);
hence, the behaviour is undefined. Anything could happen...
puts(s);
return 0;
}


--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++

Nov 14 '05 #13

P: n/a
"Emmanuel Delahaye" <em***@YOURBRAnoos.fr> writes:
(supersedes <mn***********************@YOURBRAnoos.fr>)

iru_muzgo wrote on 29/04/05 :
void
ptr_tralha(char *s)
{
while (*s != '\0') /* while the contents of s are
different * from NULL */
NULL is off-topic here.


NULL isn't off-topic, it's merely wrong.
You meant 0.


Yes, or '\0'.

[snip]

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 14 '05 #14

P: n/a
"Emmanuel Delahaye" <em***@YOURBRAnoos.fr> writes:
Nascimento wrote on 29/04/05 : [...]
for( i = 0; i < num-1; i++ )
strcpy(tralha, strcat(tralha,"#"));


Note that this is dangerous. The order of execution of the parameters
is defined by the implementation. BTW, chances are that strcat() is
called before strcpy().


Actually, I think it's guaranteed that strcat() will be called before
strcpy(). The order of evaluation of the arguments is unspecified,
but the function can't be called until all its arguments have been
evaluated; there's a sequence point between the evaluation of the
arguments and the actual call. It's bad code, but not for that
reason.
Additionally, strcpy() only works with non
overlapping strings. Your construction doesn't guarantee that.
In fact, it guarantees that the strings do overlap.

[...]
As a rule of thumb, don't use functions as a parameter to another
function. In mosts cases, it hurts...


I don't agree. It can be dangerous if you're dealing with pointers to
the same chunk of memory, but there's nothing wrong with using
function results as arguments in general.

printf("Length of string is %d\n", (int)strlen(s));

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 14 '05 #15

P: n/a
On 29 Apr 2005 14:04:10 -0700,
Nascimento <un************@gmail.com> wrote
in Msg. <cb**************************@posting.google.com >
Hello,

How to I do to return a string as a result of a function.


All the answers you ever needed were already given. Here's a summary
(which I only post to reflect ,y own knowledge on the subject matter --
this is an invitation to the gurus to tear it apart).

1. Declare a static array of char in your function and return it (as the
asctime() function does). Simple but very limited.
Problem: printf("%s %s\n", foo(a), foo(b)); prints the same thing twice.

2. malloc() memory for the string inside your function and return pointer
to it. Simple but ugly because you have to remember to free the memory
later. Problem: printf("%s\n", foo(a)); is a memory leak. Also if the
function is tucked away in some library you have to make an effort to
provide a way to use an alternative allocation function.

3. Pass an already allocated buffer and its size to your function. Most
flexible but awkward, especially if all you want is to print some quantity
in a special format. Problem: Function must check buffer overflow and
signal error when buffer is too small.

All three methods have their respective drawbacks, so you must select the
one best suited to your purpose.

--Daniel
Nov 14 '05 #16

P: n/a
On Fri, 29 Apr 2005 23:56:05 GMT, Keith Thompson <ks***@mib.org>
wrote:
Alan Balmer <al******@att.net> writes:
On 29 Apr 2005 14:04:10 -0700, un************@gmail.com (Nascimento)
wrote:[...]
{
int i;
char tralha[num];


You can't declare a variable size array.


Yes you can, if you have a C99 compiler or a pre-C99 compiler that
supports the feature. (The form of the diagnostics implies that he's
probably using gcc, which does support VLAs.)

Quite right. I've been in C89 mode too long (since somewhat before
1989 :-)
I covered the portability issues in my previous followup.


--
Al Balmer
Balmer Consulting
re************************@att.net
Nov 14 '05 #17

P: n/a
Daniel Haude <ha***@kir.physnet.uni-hamburg.de> writes:
On 29 Apr 2005 14:04:10 -0700,
Nascimento <un************@gmail.com> wrote
in Msg. <cb**************************@posting.google.com >
Hello,

How to I do to return a string as a result of a function.
All the answers you ever needed were already given. Here's a summary
(which I only post to reflect ,y own knowledge on the subject matter --
this is an invitation to the gurus to tear it apart).


Good answers, but I have a couple of quibbles.
1. Declare a static array of char in your function and return it (as the
asctime() function does). Simple but very limited.
Problem: printf("%s %s\n", foo(a), foo(b)); prints the same thing twice.
I've used a variant of this. I had a function returning char* that
declared two local static variables, an array of arrays of char (for
the results), and an index. On each call, it would cycle the index
through the array and use a fresh sub-array for the result. This
allowed, say, half a dozen distinct calls to be active simultaneously.
It's not pretty, and it still forces you to decide in advance both how
big the result can be and how many distinct results you need, but it's
a bit more flexible than using a single static array.
2. malloc() memory for the string inside your function and return pointer
to it. Simple but ugly because you have to remember to free the memory
later. Problem: printf("%s\n", foo(a)); is a memory leak. Also if the
function is tucked away in some library you have to make an effort to
provide a way to use an alternative allocation function.
Why does tucking it away in some library imply that you need to
support an alternative allocation function? There may be (or may not)
an issue for functions that are part of the standard library <OT>and
kernel code may not be able to use malloc()</OT>, but in most cases
there's no reason a library function can't use malloc().
3. Pass an already allocated buffer and its size to your function. Most
flexible but awkward, especially if all you want is to print some quantity
in a special format. Problem: Function must check buffer overflow and
signal error when buffer is too small.
Actually, it seems to me that #2 is the most flexible technique. It
allows the function itself to determine exactly how much memory it
needs, and imposes minimal complexity on the call (apart from the need
to free the allocated memory).
All three methods have their respective drawbacks, so you must select the
one best suited to your purpose.


Yes.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 14 '05 #18

P: n/a
Keith Thompson wrote:

Daniel Haude <ha***@kir.physnet.uni-hamburg.de> writes:
On 29 Apr 2005 14:04:10 -0700,
Nascimento <un************@gmail.com> wrote
in Msg. <cb**************************@posting.google.com >
Hello,

How to I do to return a string as a result of a function.


All the answers you ever needed were already given. Here's a summary
(which I only post to reflect ,y own knowledge on the subject matter --
this is an invitation to the gurus to tear it apart).


Good answers, but I have a couple of quibbles.
1. Declare a static array of char in your
function and return it (as the
asctime() function does). Simple but very limited.
Problem: printf("%s %s\n", foo(a), foo(b));
prints the same thing twice.


I've used a variant of this. I had a function returning char* that
declared two local static variables, an array of arrays of char (for
the results), and an index. On each call, it would cycle the index
through the array and use a fresh sub-array for the result. This
allowed, say, half a dozen distinct calls to be active simultaneously.
It's not pretty, and it still forces you to decide in advance both how
big the result can be and how many distinct results you need, but it's
a bit more flexible than using a single static array.
2. malloc() memory for the string inside your function
and return pointer
to it. Simple but ugly because you have to remember
to free the memory
later. Problem: printf("%s\n", foo(a));
is a memory leak. Also if the
function is tucked away in some library you have
to make an effort to
provide a way to use an alternative allocation function.


Why does tucking it away in some library imply that you need to
support an alternative allocation function? There may be (or may not)
an issue for functions that are part of the standard library <OT>and
kernel code may not be able to use malloc()</OT>, but in most cases
there's no reason a library function can't use malloc().
3. Pass an already allocated buffer and its size to your function.
Most
flexible but awkward,
especially if all you want is to print some quantity
in a special format.
Problem: Function must check buffer overflow and
signal error when buffer is too small.


Actually, it seems to me that #2 is the most flexible technique. It
allows the function itself to determine exactly how much memory it
needs, and imposes minimal complexity on the call (apart from the need
to free the allocated memory).


I'm partial to number 3.
Actually the called function doesn't have to do any checking or
signaling as long the programmer considers the onus to
be on the calling function to supply a buffer large enough.
With number 3 you can use any kind of object,
automatic, static or allocated.
If an allocated object is used, then it is allocated and freed
in the same function, which is good.

#include <limits.h>
#include <stddef.h>
#include <stdio.h>

#define E_TYPE unsigned char
#define P_TYPE unsigned
#define STRING " %s = 0x%x\n"
#define INITIAL 0
#define FINAL 0xf
#define OFFSET (sizeof(e_type) * CHAR_BIT - 4)
#define INC(E) (++(E))

typedef E_TYPE e_type;
typedef P_TYPE p_type;

void bitstr(char *str, const void *obj, size_t n);

int main(void)
{
e_type e;
char ebits[CHAR_BIT * sizeof e + 1];

puts("\n/* BEGIN output from bitstr.c */\n");
for (e = INITIAL; FINAL >= e; INC(e)) {
bitstr(ebits, &e, sizeof e);
printf(STRING, OFFSET + ebits, (p_type)e);
}
puts("\n/* END output from bitstr.c */");
return 0;
}

void bitstr(char *str, const void *obj, size_t n)
{
unsigned mask;
const unsigned char *byte = obj;

while (n-- != 0) {
mask = ((unsigned char)-1 >> 1) + 1;
do {
*str++ = (char)(mask & byte[n] ? '1' : '0');
mask >>= 1;
} while (mask != 0);
}
*str = '\0';
}

--
pete
Nov 14 '05 #19

P: n/a
Keith Thompson wrote:
.... snip ...
I've used a variant of this. I had a function returning char* that
declared two local static variables, an array of arrays of char (for
the results), and an index. On each call, it would cycle the index
through the array and use a fresh sub-array for the result. This
allowed, say, half a dozen distinct calls to be active simultaneously.
It's not pretty, and it still forces you to decide in advance both how
big the result can be and how many distinct results you need, but it's
a bit more flexible than using a single static array.


I have used a system that looked roughly like this:

#define BUFSIZE 20
#define NBUFS 9 /* or whatever */

struct abuf {struct abuf *next; char buf[BUFSIZE]};

static struct abuf *initbuffs(void)
{
struct abuf *nxt, *first;
int i;

first = nxt = malloc(sizeof *nxt); /* No error testing */
first->buf = "";
for (i = NBUFS; i; i--) {
nxt->next = malloc(sizeof *(nxt->next));
nxt->buf = "";
}
return (nxt->next = first); /* forming ring buffer */
} /* initbuffs */

/* ------------------- */

char *getbuf(void)
{
static struct abuf *curbuff;

if (!curbuff) curbuff = initbuffs();
curbuff = curbuff->next;
return curbuff->buf;
} /* getbuf */

which does all its allocating on the very first call. Nothing
outside this code need know how it is built.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #20

P: n/a
Keith Thompson <ks***@mib.org> writes:
Daniel Haude <ha***@kir.physnet.uni-hamburg.de> writes:
[snip]
1. Declare a static array of char in your function and return it (as the
asctime() function does). Simple but very limited.
Problem: printf("%s %s\n", foo(a), foo(b)); prints the same thing twice.


I've used a variant of this. I had a function returning char* that
declared two local static variables, an array of arrays of char (for
the results), and an index. On each call, it would cycle the index
through the array and use a fresh sub-array for the result. This
allowed, say, half a dozen distinct calls to be active simultaneously.
It's not pretty, and it still forces you to decide in advance both how
big the result can be and how many distinct results you need, but it's
a bit more flexible than using a single static array.


A single function can do this for lots of other functions:

const char *
semi_permanent_copy( const char * s ){
static char buffer[ SOME_SIZE ];
static size_t next = 0;
size_t needed;

if( s == NULL ) return NULL; /* a plausible choice */

if( (needed = strlen(s) + 1) > SOME_SIZE ) die( "no space" );

if( needed > SOME_SIZE - next ) next = 0;

next += needed;
memcpy( & buffer[ next - needed ], s, needed );
return & buffer[ next - needed ];
}

Client functions would have their own local (auto) buffers, and use

return semi_permanent_copy( local_buffer );

to return "semi-permanent" results.

Allocating out of a single buffer means there can be more strings if
they are shorter, or longer strings if there aren't as many. Also,
with all the clients sharing a single buffer, it's easier to feel good
about having a generously sized buffer, which will reduce the chance
of exceeding a fixed limit.

The return type being 'const' helps make sure strings in the buffer
aren't mistakenly overwritten, and increases the likelihood that the
results won't be held on to for too long. If a non-const version is
desired, just wrap one function around another:

char *
semi_permanent_writeable_copy( const char *s ){
... as above ...
}

const char *
semi_permanent_copy( const char *s ){
return semi_permanent_writeable_copy( s );
}

Following what I think is good practice, the safer version has the
shorter, easier name. Strictly speaking, the second function here
isn't necessary, because return results that are 'const' will
automatically convert if the writeable version is used. But having
the safer 'const' version be the default increases the chance that
clients will make conscious and considered decisions and use the
writeable version only where really necessary.

Disclaimer: I've used code much like this, but what's here is just
typed in, not compiled or tested.
Nov 14 '05 #21

P: n/a

In article <ln************@nuthaus.mib.org>, Keith Thompson <ks***@mib.org> writes:
Daniel Haude <ha***@kir.physnet.uni-hamburg.de> writes:
3. Pass an already allocated buffer and its size to your function. Most
flexible but awkward, especially if all you want is to print some quantity
in a special format. Problem: Function must check buffer overflow and
signal error when buffer is too small.


Actually, it seems to me that #2 is the most flexible technique. It
allows the function itself to determine exactly how much memory it
needs, and imposes minimal complexity on the call (apart from the need
to free the allocated memory).


I can think of at least one case where #3 provides added flexibility:
when you want the output inserted into the middle of an already-
allocated buffer. Then you can pass a pointer to that offset and the
length of the remaining area in the buffer, and avoid the allocation
and copying required with #2.

Obviously this is just another case where the optimal method depends
on the application, as I believe we all agree.

--
Michael Wojcik mi************@microfocus.com

Art is our chief means of breaking bread with the dead ... but the social
and political history of Europe would be exactly the same if Dante and
Shakespeare and Mozart had never lived. -- W. H. Auden
Nov 14 '05 #22

P: n/a
On Mon, 02 May 2005 18:45:30 GMT,
Keith Thompson <ks***@mib.org> wrote
in Msg. <ln************@nuthaus.mib.org>
Why does tucking it away in some library imply that you need to
support an alternative allocation function? There may be (or may not)
an issue for functions that are part of the standard library <OT>and
kernel code may not be able to use malloc()</OT>, but in most cases
there's no reason a library function can't use malloc().


There's nothing wrong with it unless you use some malloc() wrapper for
debugging purposes which would result in a mixture of buffers created
by the "native" malloc (as returned by our library) and those created by
the debugging wrapper. Of course if this is an issue, nothing keeps us
from adding a malloc/free registering function to the library for those
that want it. IIRC libcurl has such a feature.

--Daniel
Nov 14 '05 #23

P: n/a
On Sat, 30 Apr 2005 08:27:42 +0200, "Emmanuel Delahaye"
<em***@YOURBRAnoos.fr> wrote:

<snip other points already dealt with>
strcpy(tralha, strcat(tralha,"#"));
<snip> (To the gurus : [C99] shouldn't the 'restrict' keyword used here by the
compiler to generate some warning ?)


The standard does not _require_ a diagnostic for 'restrict' parameters
(or pointers generally) that improperly overlap. It does provide
information that a compiler could use in at least some simple cases
like this one to provide such a diagnostic as a good-QoI matter.

However there are many (important) cases where no compiler could
detect the error at compile time (and the "spirit" of C is not to
impose the cost of doing so at run time) so there is the risk, as with
other 'easy case' warnings, that programmers get 'lazy' and come to
expect and rely on the compiler to detect certain problems.

- David.Thompson1 at worldnet.att.net
Nov 14 '05 #24

This discussion thread is closed

Replies have been disabled for this discussion.