Value-returning or Void functions??

I was studying some of the inbuilt functions in the Standard C++ library from the Reference section on this site and observed a confounding pattern in the concept of the return types of some of the functions. Consider the functions strcpy and strcat whose function prototypes are:

1
2
char * strcpy ( char * destination, const char * source );   {copy string)
char * strcat ( char * destination, const char * source );   (concatenate strings)


and the corresponding examples below culled from the pages describing these functions:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* strcpy example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str1[]="Sample string";
  char str2[40];
  char str3[40];
  strcpy (str2,str1);
  strcpy (str3,"copy successful");
  printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
  return 0;
}




/* strcat example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[80];
  strcpy (str,"these ");
  strcat (str,"strings ");
  strcat (str,"are ");
  strcat (str,"concatenated.");
  puts (str);
  return 0;
}


Each of the function prototypes quotes the return type to be of type char* (hence, I consider them as value-/pointer- returning functions; but in the examples shown above, the functions were invoked as void functions, i.e. like stand-alone functions!! This would refer to lines 10-11 in the first example and lines 26-29 in the second example. Why is this so?

As the internal code of these functions is inaccessible, I'm just wondering why the functions were not made to be void functions and the formal parameter destination made a reference parameter; this way, any changes within the inaccessible body of the function is reflected in the user's actual parameter. Any insights please?
Each of the function prototypes quotes the return type to be of type char* (hence, I consider them as value-/pointer- returning functions; but in the examples shown above, the functions were invoked as void functions, i.e. like stand-alone functions!! This would refer to lines 10-11 in the first example and lines 26-29 in the second example. Why is this so?

Even if a function returns a value, the calling code doesn't have to do anything with that value, so lines 10 - 11 and 26-29 are totally legal. The functions still execute, and the effects of those function still occur.

As the internal code of these functions is inaccessible, I'm just wondering why the functions were not made to be void functions and the formal parameter destination made a reference parameter; this way, any changes within the inaccessible body of the function is reflected in the user's actual parameter. Any insights please?

You need to think a bit more precisely about what's going on with those parameters. Note that destination is a pointer to memory. It is assumed that the memory has been correctly allocated, so that it's reserved for the data that's going to be copied/concatenated into it.

The functions don't change the values of the pointers; that is, they don't change the address of the memory into which the copied/concatenated data is going to be stored. The functions do, however, change the data which is stored in the memory at that address.

So the calling code does indeed see the changes that have been made to that memory, even though the value of the pointer itself hasn't changed.
Last edited on
1. C does not have references.

2. Those functions return the destination. In a sense they behave similarly to assignment. Have you ever seen:
1
2
3
4
5
char x;
if ( EOF != (x = fgetc(pFile)) )
{
 // something
}

Similarly, one could:
1
2
3
4
if ( '\0' != *(strcpy(dst, src)) )
{
 // something
}

Yes, most of the time the return value is unnecessary, but we can trust the compiler to optimise away the unnecessary instructions.
Last edited on
@MikeyBoy: I agree with almost all you said BUT my point still holds true though. What difference does it make if the function prototypes were respectively declared as:

1
2
void strcpy ( char *& destination, const char * source );      (copy string)
void strcat ( char *& destination, const char * source );      (concatenate strings)

I have changed the return types to void and made the first argument of each function a reference parameter. The functions would still have worked correctly, right? If yes, then keskiverto's statement:

Yes, most of the time the return value is unnecessary, but we can trust the compiler to optimise away the unnecessary instructions.

sorts of agree with my critique of the return type used for the functions in the library!
You are free to disagree with the C and C++ standard committees. Just don't do it on any production system.
geeloso wrote:
[sort of agrees] with my critique of the return type used for the functions in the library!

No, it directly contradicts it. keskiverto even gave you examples where such constructs are useful.

Sure, you could write all your code as a collection of variables, then functions, then tests, but C is specifically designed to be a little more friendly than that, so you can make concise, readable statements.

Believe it or not, it actually comes in handy sometimes.
made the first argument of each function a reference parameter
But those functions came from and compatible with C standard library where references did nit exist.

The functions would still have worked correctly, right?
You lost ability to use them in functional context and use function chaining.

made the first argument of each function a reference parameter

On top of the fact that these are C functions, as others have already pointed out...

A reference to what? As I've already explained, the value of that pointer does not change. So what would be achieved by making it a reference?
Last edited on
Topic archived. No new replies allowed.