Return pointer from function

L

Liviu

Say i have a function:

char *rmtrail(char *str)
{
if (str)
{
int i;

for (i = strlen(str) - 1; i >= 0 && isspace(str); --i)
;
str[++i] = '\0';
}

return str;
}

that removes trailing spaces from a string. The result of this
function will be different, if I change the return type from char* to
void and remove 'return str' ? I mean, in the caller function i call
rmtrail, passing a pointer to string. Even though in rmtrail, i
received a copy of the pointer to my string, the modified string will
be the same, so where's the need to return 'str' from rmtrail
function ? This function was not coded by me, but it works fine.
I just want to know if there is any difference...
 
R

Richard Bos

Liviu said:
Say i have a function:

char *rmtrail(char *str)
{
if (str)
{
int i;

for (i = strlen(str) - 1; i >= 0 && isspace(str); --i)
;
str[++i] = '\0';
}

return str;
}

that removes trailing spaces from a string. The result of this
function will be different, if I change the return type from char* to
void and remove 'return str' ? I mean, in the caller function i call
rmtrail, passing a pointer to string. Even though in rmtrail, i
received a copy of the pointer to my string, the modified string will
be the same, so where's the need to return 'str' from rmtrail
function ? This function was not coded by me, but it works fine.
I just want to know if there is any difference...


The difference will be in the way you can call it, but functionally, it
will indeed remain the same. Compare this with, say, strcpy(); it, too,
returns a pointer to the string you just copied, which is the very same
pointer you passed in. That's the way you have it now. Both strcpy() and
your function could return nothing and remain functionally the same,
eliminating only some not very readable constructs such as
strcpy(rmtrail(strcat(rmtrail(......))));.
IMO, both functions would be improved if they returned a pointer, not to
the first, but to the last character of their results. That way, you
could at least use the result for slightly more efficient string
construction.

Richard
 
L

Liviu

Liviu said:
Say i have afunction:
char *rmtrail(char *str)
{
if (str)
{
int i;
for (i = strlen(str) - 1; i >= 0 && isspace(str); --i)
;
str[++i] = '\0';
}
returnstr;
}

that removes trailing spaces from a string. The result of this
functionwill be different, if I change thereturntype from char* to
void and remove 'returnstr' ? I mean, in the callerfunctioni call
rmtrail, passing apointerto string. Even though in rmtrail, i
received a copy of thepointerto my string, the modified string will
be the same, so where's the need toreturn'str' from rmtrail
function? Thisfunctionwas not coded by me, but it works fine.
I just want to know if there is any difference...


The difference will be in the way you can call it, but functionally, it
will indeed remain the same. Compare this with, say, strcpy(); it, too,
returns apointerto the string you just copied, which is the very samepointeryou passed in. That's the way you have it now. Both strcpy() and
yourfunctioncouldreturnnothing and remain functionally the same,
eliminating only some not very readable constructs such as
strcpy(rmtrail(strcat(rmtrail(......))));.
IMO, both functions would be improved if they returned apointer, not to
the first, but to the last character of their results. That way, you
could at least use the result for slightly more efficient string
construction.

Richard


I understand now. So, as long as i dont need the result of my function
'rmtrail' as a parameter to other function (making an not so readable
syntax) i can change the returned type (to void) without any bad
consequnces.
Thank you.
 
C

CBFalconer

Liviu said:
Say i have a function:

char *rmtrail(char *str) {
if (str) {
int i;
for (i = strlen(str) - 1; i >= 0 && isspace(str); --i) ;
str[++i] = '\0';
}
return str;
} /* edited for space, cbf */


As written that function is a usage trap. One is likely to write
something like:

printf("%s\n%s\n", str, rmtrail(str));

and expect to get two different strings. You won't. By making the
function return an error indicator, or a void, you avoid that trap.
 
K

Keith Thompson

Liviu said:
Liviu said:
Say i have afunction:

char *rmtrail(char *str)
{
if (str)
{
int i;

for (i = strlen(str) - 1; i >= 0 && isspace(str); --i)
;
str[++i] = '\0';
}

returnstr;
}
[...]
I understand now. So, as long as i dont need the result of my function
'rmtrail' as a parameter to other function (making an not so readable
syntax) i can change the returned type (to void) without any bad
consequnces.


Yes. Or you can leave the function as it is, and just ignore the
returned result if you don't happen to need it.
 
L

Liviu

Liviu said:
Say i have a function:
char *rmtrail(char *str) {
if (str) {
int i;
for (i = strlen(str) - 1; i >= 0 && isspace(str); --i) ;
str[++i] = '\0';
}
return str;
} /* edited for space, cbf */


As written that function is a usage trap. One is likely to write
something like:

printf("%s\n%s\n", str, rmtrail(str));

and expect to get two different strings. You won't. By making the
function return an error indicator, or a void, you avoid that trap.


It's true...I often use this construct in C#.
 
F

Flash Gordon

dykeinthebox wrote, On 27/06/07 17:13:
Say i have afunction:
char *rmtrail(char *str)
{
if (str)
{
int i;
for (i = strlen(str) - 1; i >= 0 && isspace(str); --i)
;
str[++i] = '\0';
}
returnstr;
}


This function invokes undefined behavior when called with a whitespace-only
string.


Where? The final loops will have..
--i; /* i is now 0 */
i >=0 /* true, so continue */
isspace(str) /* true so continue */
--i; /* i is now -1 */
i >=0 /* false, so the sub-expression after && not executed and loop
ends */
str[++i] = '\0'; /* value of i+1 used, i.e. str[0] = '\0' */

The problems are, I think

1) with an empty string if SIZE_MAX>INT_MAX (often the case) as
(size_t)0 - 1 will give SIZE_MAX and I don't *think* you are guaranteed
that this will make i negative, although all I think it likely to work
with implementations I know

2) with strlen(str)>INT_MAX, where obviously it won't fit in i!

The following minimally changed version is safe.

char *rmtrail(char *str)
{
if (str && str[0]) {
size_t i;
for (i = strlen(str) - 1;
i != SIZE_MAX && isspace((unsigned char)str); --i)
continue;
str[++i] = '\0';
}
return str;
}

Note the cast to unsigned char!

Personally I would probably do something more like:
char *rmtrail(char *str)
{
if (str && *str) {
size_t i = strlen(str);
while (--i && isspace((unsigned char)str))
continue;
str[i+1] = '\0';
}
return str;
}

Or maybe
char *rmtrail(char *str)
{
if (str) {
char *end = str + strlen(str);
while (end>str && isspace((unsigned char)*--end))
continue;
*end = '\0';
}
return str;
}

Note that the above is all untested.
 
A

Army1987

CBFalconer said:
Liviu said:
Say i have a function:

char *rmtrail(char *str) {
if (str) {
int i;
for (i = strlen(str) - 1; i >= 0 && isspace(str); --i) ;
str[++i] = '\0';
}
return str;
} /* edited for space, cbf */


As written that function is a usage trap. One is likely to write
something like:

printf("%s\n%s\n", str, rmtrail(str));

and expect to get two different strings. You won't.

Why? There is a sequence point after each conversion specifier in
printf, so the first %s will print the old str.
 
A

Army1987

Walter Roberson said:
First time I've ever seen that claim. Citation, please?
7.19.1p1:
The formatted input/output functions shall behave as if there is a sequence point after the

actions associated with each specifier.
 
W

Walter Roberson

Walter Roberson said:
7.19.1p1:
The formatted input/output functions shall behave as if there is a sequence point after the
actions associated with each specifier.

Interesting. But is it applicable? The arguments to the formatted
I/O functions are evaluated before the function is called
(there is a sequence point after the evaluation of the parameters
but before the call), so if there are side effects in the parameters
they take place before you get around to the examination of the
conversion specifiers.
 
A

Army1987

Walter Roberson said:
Walter Roberson said:
Interesting. But is it applicable? The arguments to the formatted
I/O functions are evaluated before the function is called
(there is a sequence point after the evaluation of the parameters
but before the call), so if there are side effects in the parameters
they take place before you get around to the examination of the
conversion specifiers.
Yes. I realized that about one minute after I hit "Send".
I was just about to point out that.

The Italian proverb "Before speaking, count to ten" is insufficient. It should be changed to "... count to 120" at least.
 
C

CBFalconer

Army1987 said:
7.19.1p1:
The formatted input/output functions shall behave as if there is
a sequence point after the actions associated with each specifier.

It's 7.19.6. At least in N869.
 
R

Richard Heathfield

Army1987 said:
"CBFalconer" <[email protected]> ha scritto nel messaggio


Why? There is a sequence point after each conversion specifier in
printf, so the first %s will print the old str.

Irrelevant, since the evaluation of arguments will happen before printf
is even called, let alone at the point where it's wandering through its
format string.

But why listen to me? Watch, instead:

me@here> cat foo.c
#include <stdio.h>
#include <string.h>

char *test(char *s)
{
strcpy(s, "If I see this twice, you're wrong.");
return s;
}

int main(void)
{
char buf[128] = "If I see this even once, you're right.";
printf("[%s]\n[%s]\n", buf, test(buf));
return 0;
}
me@here> ./foo
[If I see this twice, you're wrong.]
[If I see this twice, you're wrong.]

So either you're wrong, or gcc -W -Wall -ansi -pedantic
-Wformat-nonliteral -Wcast-align -Wpointer-arith -Wbad-function-cast
-Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
-Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wconversion
-Wwrite-strings -Wno-conversion -ffloat-store -O2 is broken. Which do
you think is more likely?
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,125
Latest member
VinayKumar Nevatia_
Top