strings and functions

C

c_monty

I am used to Delphi and VB, where functions can return strings. I
recently starting learning C and my findings are that you can have
external functions build strings, but the function cannot return the
string itself, rather, it needs to update a variable that is an array or
points to an array. Correct?



Below is a 'simple' test to work with a string that was created in an
external function (and external file). Based on the result I get (_@),
I know I don't fully "get it" yet. Any help would be appreciated.



//MAIN.C

#include<stdio.h>



main()

{

char *data_from_function;



my_function(data_from_function);

printf("Data results from My Function: %s\n");

}



//MYFUNCTION.C



my_function(char *strData)

{

strData = "HELLO WORLD\n";

}



(Linux 9 i386)

#gcc main.c myfunction.c

#./a.out



Data results from My Function: _@
 
T

Thomas Matthews

c_monty said:
I am used to Delphi and VB, where functions can return strings. I
recently starting learning C and my findings are that you can have
external functions build strings, but the function cannot return the
string itself, rather, it needs to update a variable that is an array or
points to an array. Correct?

Below is a 'simple' test to work with a string that was created in an
external function (and external file). Based on the result I get (_@),
I know I don't fully "get it" yet. Any help would be appreciated.

//MAIN.C

#include<stdio.h>
main()

The main() function should have a return type:
int main(void)

{
char *data_from_function;
my_function(data_from_function);
printf("Data results from My Function: %s\n");

Perhaps this should have been:
printf("Data results from my_function: %s\n",
data_from_function); /* you forgot this */
//MYFUNCTION.C
my_function(char *strData)
{
strData = "HELLO WORLD\n";
}

Pointers are passed by value in C.
If you want to change a pointer, pass the address
or a pointer to the pointer:
void my_function(char * * strData)
{
*strData = "Hellow World\n";
}

or copy the data to the location of the original
array:
void my_other_function(char * strData)
{
strcpy(strdata, "Hello again.\n");
return;
}

int main(void)
{
char string_one[640];
char * string_two;

my_function(&string_two);
my_other_function(string_one);
printf("Results:\n%s\n%s\n",
string_one, string_two);
return 0;
}
 
E

Eric Sosman

c_monty said:
I am used to Delphi and VB, where functions can return strings. I
recently starting learning C and my findings are that you can have
external functions build strings, but the function cannot return the
string itself, rather, it needs to update a variable that is an array or
points to an array. Correct?

Pretty much. "C functions can't return strings" is just
a special case of "C functions can't return arrays," because
a string in C is just an array of `char' elements formatted
in a particular way. Recommended reading: Section 6 "Arrays
and Pointers" in the comp.lang.c Frequently Asked Questions
(FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html
Below is a 'simple' test to work with a string that was created in an
external function (and external file). Based on the result I get (_@),
I know I don't fully "get it" yet. Any help would be appreciated.

//MAIN.C

#include<stdio.h>

main()

{

char *data_from_function;

my_function(data_from_function);

printf("Data results from My Function: %s\n");

There are minor solecisms elsewhere, but this is the first
Real Live Error: You've used the "%s" specifier to tell printf()
to output a string, but you haven't told printf() what string
you want it to output! printf() trusts you, looks in the place
where the string's `char*' pointer would have been if you'd
supplied one, gets some kind of garbage, and then there's no
guarantee of what might happen. You've landed yourself in the
perilous land called Undefined Behavior.
}

//MYFUNCTION.C

my_function(char *strData)

{

strData = "HELLO WORLD\n";

Here's the second Real Live Error: You don't understand
that C arguments are passed by value, not by reference.
See Question 4.8 in the FAQ.
}

(Linux 9 i386)

#gcc main.c myfunction.c

Since you're still somewhat shaky in C, it would be a
good idea to crank up gcc's warning levels a bit. I use

gcc -Wall -W -ansi -pedantic -O2 ...

.... except that I omit "-ansi -pedantic" for programs that
can't tolerate such rigidity, and I raise the optimization
level higher than "-O2" when circumstances warrant it.
#./a.out

Data results from My Function: _@

Could have been anything at all, or nothing at all.
Undefined Behavior is, well, undefinable. Folks around
here are fond of saying U.B. might make demons fly out
of your nose. Years ago on this same newsgroup, people
had a wider variety of imaginative U.B. examples, but the
nasal demons seem to have crowded out the creativity.
 
M

Martin Dickopp

c_monty said:
I am used to Delphi and VB, where functions can return strings. I
recently starting learning C and my findings are that you can have
external functions build strings, but the function cannot return the
string itself, rather, it needs to update a variable that is an array or
points to an array. Correct?
Correct.

Below is a 'simple' test to work with a string that was created in an
external function (and external file). Based on the result I get (_@),
I know I don't fully "get it" yet. Any help would be appreciated.

//MAIN.C

#include<stdio.h>

main()

int main (void)
{
char *data_from_function;

my_function(data_from_function);

printf("Data results from My Function: %s\n");

Do you mean `printf("Data results from My Function: %s\n", data_from_function);'?

Insert `return 0;' before the closing brace.
//MYFUNCTION.C

my_function(char *strData)
{
strData = "HELLO WORLD\n";
}

`strData' is local to `my_function'. You make `strData' point to a string
literal. Then the function execution ends, and the value of `strData' is
forgotten.

You can return a string literal (more precisely: a pointer to the first
character of string literal) from a function like this:


#include <stdio.h>

const char *my_function (void)
{
return "HELLO WORLD";
}

int main (void)
{
printf ("Data results from My Function: %s\n", my_function ());
return 0;
}


A string literal cannot be modified. If you need to modify the string, you
must copy it to an array:


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

void my_function (char *const buffer)
{
strcpy (buffer, "HELLO WORLD");
}

int main (void)
{
/* Must be large enough for the string,
including the terminating '\0' character. */
char my_buffer [12];

my_function (my_buffer);

my_buffer [1] = 'A';

printf ("Data results from My Function: %s\n", my_buffer);
return 0;
}

(Linux 9 i386)

<OT>
No such thing. Linux is currently at version 2.4.21; the development branch
is at version 2.6.0-test3.
#gcc main.c myfunction.c

Please invoke gcc with at least the following flags: -O -Wall -ansi -pedantic

I recommend `-W' in addition to that.

Martin
 
E

Ed Morton

c_monty wrote:
char *my_function(char *strData)
{
strData = malloc(sizeof "HELLO WORLD\n");
if (strData) {
strcpy(strData, "HELLO WORLD\n");
}
return strData;
}

Why would you have "my_function" take an argument in this case? Wouldn't you
really write this as:

char *my_function()
{
char *strData;
strData = malloc(sizeof "HELLO WORLD\n");
if (strData) {
strcpy(strData, "HELLO WORLD\n");
}
return strData;
}

so that instead of being called as:
data_from_function = my_function(data_from_function);

it can be called as:

data_from_function = my_function();

Regards,

Ed.
 
A

ataru

Thomas Matthews said:
void my_function(char * * strData)
{
*strData = "Hellow World\n";
}

This is bad (right?) since strData now points to a constant string that will
vanish when my_function returns...
void my_other_function(char * strData)
{
strcpy(strdata, "Hello again.\n");
return;
}

Also bad, since you don't know in general how much space strData has
associated with it, if any.

If I've done foot-in-mouth again here, I apologize ;)
 
M

Michael B Allen

I am used to Delphi and VB, where functions can return strings. I
recently starting learning C and my findings are that you can have
external functions build strings, but the function cannot return the
string itself, rather, it needs to update a variable that is an array or
points to an array. Correct?

These other environments are likely returning pointers (Java calls them
references) as well. C permits pointer arthmetic which gives C it's
razor's edge. Be careful.
my_function(data_from_function);

printf("Data results from My Function: %s\n");

You just forgot to add the string you want to print:

printf("Data results from My Function: %s\n", data_from_function);

In C the way to "return strings" is to return a pointer to an array
of characters:

char *
tostr(void)
{
return "hello";
}

Mike
 
P

pete

Ed said:
Why would you have "my_function" take an argument in this case?

It's a vestigial feature from the original post.
Wouldn't you really write this as:

char *my_function()
{
char *strData;
strData = malloc(sizeof "HELLO WORLD\n");
if (strData) {
strcpy(strData, "HELLO WORLD\n");
}
return strData;
}

so that instead of being called as:


it can be called as:

data_from_function = my_function();

Yes, I think that's better.
 
P

pete

This is bad (right?) since strData now points to a
constant string that will vanish when my_function returns...

No. Those kinds of strings persist.
The strData pointer itself, will disappear,
but the desired side effect will happen.
The external pointer that *strData points to,
will be pointed at the string.
Also bad, since you don't know in general how much space strData has
associated with it, if any.

That particular criticism is valid.

This works:

#include <stdio.h>

void my_function(char * * strData)
{
*strData = "Hellow World\n";
}

int main(void)
{
char *data_from_function;

my_function(&data_from_function);
printf("Data results from My Function: %s\n",
data_from_function);
return 0;
}
 
T

Thomas Matthews

This is bad (right?) since strData now points to a constant string that will
vanish when my_function returns...

No, the location of the literal will persist.


Also bad, since you don't know in general how much space strData has
associated with it, if any.

If I've done foot-in-mouth again here, I apologize ;)

Yes, this is also bad, but it is another alternative.
Welcome to the problem with C arrays.
 
C

Christopher Benson-Manica

No. Those kinds of strings persist.
The strData pointer itself, will disappear,
but the desired side effect will happen.
The external pointer that *strData points to,
will be pointed at the string.

So, since it's a string literal, it still ends up in the static section of
memory or something? The function still doesn't work if strData happens to be
NULL... And even if it does work, you can't do something like
*strData[3]='a', right, since the string is literal?
 
A

ark

pete said:
Christopher Benson-Manica wrote:
Something like that.
The function still doesn't work if strData happens to be
NULL... And even if it does work, you can't do something like
*strData[3]='a', right, since the string is literal?

Yes, you can't do something like that, because of that.

Being a practitioner, cannot remember what the std says, but I've seen
different things. A string literal can be a const (in which case, the linker
can collect identical strings in one) or not. I've seen it also as a
compiler switch.
arkk at macroexpressions.com
 
P

pete

ark said:
pete said:
Christopher Benson-Manica wrote:
Something like that.
The function still doesn't work if strData happens to be
NULL... And even if it does work, you can't do something like
*strData[3]='a', right, since the string is literal?

Yes, you can't do something like that, because of that.
Being a practitioner, cannot remember what the std says,

http://anubis.dkuug.dk/JTC1/SC22/WG14/www/docs/n869/

It says that attempts at string literal modification,
result in undefined behavior.
When I said "you can't do that",
I meant "Doing that, isn't sanctioned by the standard",
but ..., you can attempt a lot of things that wind up working
on your system, which in fact are not sanctioned by the standard.
People frequently post code which invokes undefined behavior,
while they insist that the code is correct because it
produces the desired result on their system.

but I've seen different things.
A string literal can be a const (in which case, the linker
can collect identical strings in one) or not.

The standard says that that is allowed.
 

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,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top