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

C Strings not returning from a function

P: n/a
I've made a small program to demonstrate one problem I'm having fixing
strings in C.

I need to be able to remove HTML mark-ups from text lines.

I create my variable, pass it to my function, verify that the data has
been passed correctly and then cannot get the data back!

If I change the return to some random string literal, it comes back
fine.

All advice appreciated.

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

char * FixString(char *strIn)
{
char *strMsg = strIn;
char strTmp[40] = "";
char *strReturn = &strTmp;

int i = 0;
int j = strlen(strMsg);
for (i = 0; i <= j; ++i)
{
/* removing the cleanup code for brevity on usenet */
strTmp[i] = strMsg[i];
}

printf("%s\n", strReturn);
/* Prints out the string perfectly */

return strReturn; /* change to return "All clear" and it works fine
*/
}

int main(void)
{
char *strOut = "This is a line from a web page <br>";
char *strBack = FixString(strOut);

printf("%s\n", strBack); /* Prints garbage - why? */

return 0;
}

Sep 25 '06 #1
Share this Question
Share on Google+
47 Replies


P: n/a
pkirk25 wrote:
I've made a small program to demonstrate one problem I'm having fixing
strings in C.

I need to be able to remove HTML mark-ups from text lines.

I create my variable, pass it to my function, verify that the data has
been passed correctly and then cannot get the data back!

If I change the return to some random string literal, it comes back
fine.

All advice appreciated.

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

char * FixString(char *strIn)
{
char *strMsg = strIn;
char strTmp[40] = "";
char *strReturn = &strTmp;
Didn't your compiler give you a helpful diagnostic here? If not, turn
up its warning level or use a better compiler.
int i = 0;
int j = strlen(strMsg);
for (i = 0; i <= j; ++i)
{
/* removing the cleanup code for brevity on usenet */
strTmp[i] = strMsg[i];
}

printf("%s\n", strReturn);
/* Prints out the string perfectly */

return strReturn; /* change to return "All clear" and it works fine
You are attempting to return a pointer to a local variable, don't do
this. Either pass in the output string, or use a dynamic buffer
allocated by the function and return this.

--
Ian Collins.
Sep 25 '06 #2

P: n/a
[snip]
My complier is Visual C++ 6 wcih I know is old but it is what was
available.

I genuinely think my problems are dwon to struggling with indirection
and pointers moret han the compiler, tempting tho it is to blame
Microsoft.
>
You are attempting to return a pointer to a local variable, don't do
this. Either pass in the output string, or use a dynamic buffer
allocated by the function and return this.
Ian, if i retrun the string array strTmp that *strReturn points to, I
get the same mess.

Can you explain what you mean by "pass in the output string"? What
would I change in my code to do that? Sorry to ask to be spoon fed.

Sep 25 '06 #3

P: n/a
pkirk25 wrote:
[snip]
My complier is Visual C++ 6 wcih I know is old but it is what was
available.

I genuinely think my problems are dwon to struggling with indirection
and pointers moret han the compiler, tempting tho it is to blame
Microsoft.
A C++ compiler should refuse to compile the line you snipped;

char *strReturn = &strTmp;

Here you are attempting to initialise a char* with a char**, either use

char *strReturn = strTmp;

or

char *strReturn = &strTmp[0];
>>You are attempting to return a pointer to a local variable, don't do
this. Either pass in the output string, or use a dynamic buffer
allocated by the function and return this.


Ian, if i retrun the string array strTmp that *strReturn points to, I
get the same mess.

Can you explain what you mean by "pass in the output string"? What
would I change in my code to do that? Sorry to ask to be spoon fed.
Add an extra parameter:

char* FixString( const char* strIn, char* strOut )

Note the change of strIn to const, you aren't changing it in your
function. Use strOut where you use strTmp.

You can then call it with:

const char *strOut = "This is a line from a web page <br>"

char *backBuff = char[someSize];

char *strBack = FixString(strOut, backBuff);

--
Ian Collins.
Sep 25 '06 #4

P: n/a
Code almsot half the size and works perfectly.

Thanks!

BTW, the complier warns that malloc returns int and that my *backBuff
is not one in the line:

char *backBuff = malloc(i);

If I fix that, no more VC++ warnings.
#include <stdio.h>
#include <string.h>

char * FixString(char *strIn, char *strOut)
{
int i = 0;
int j = strlen(strIn);
for (i = 0; i <= j; ++i)
{
/* removing the cleanup code for brevity on usenet */
strOut[i] = strIn[i];
}

printf("%s\n", strOut);
return strOut;
}

int main(void)
{
char *strOut = "This is a line from a web page <br>";
int i = strlen(strOut);
char *backBuff = malloc(i);
char *strBack = FixString(strOut, backBuff);

printf("%s\n", strBack); /* Prints out the string perfectly */

return 0;
}

Sep 25 '06 #5

P: n/a
pkirk25 wrote:
Code almsot half the size and works perfectly.
Please keep some context in your replies.
Thanks!

BTW, the complier warns that malloc returns int and that my *backBuff
is not one in the line:
That's because you haven't included the required header, <stdlib.h>

--
Ian Collins.
Sep 25 '06 #6

P: n/a
"0 error(s), 0 warning(s)"

Well, that means i can go to bed!

Thanks and good night.

Sep 25 '06 #7

P: n/a
pkirk25 wrote:
"0 error(s), 0 warning(s)"

Well, that means i can go to bed!

Thanks and good night.
Didn't you see my comment about context?

--
Ian Collins.
Sep 25 '06 #8

P: n/a
Ian Collins <ia******@hotmail.comwrites:
pkirk25 wrote:
>[snip]
My complier is Visual C++ 6 wcih I know is old but it is what was
available.

I genuinely think my problems are dwon to struggling with indirection
and pointers moret han the compiler, tempting tho it is to blame
Microsoft.
A C++ compiler should refuse to compile the line you snipped;

char *strReturn = &strTmp;

Here you are attempting to initialise a char* with a char**, either use

char *strReturn = strTmp;

or

char *strReturn = &strTmp[0];
A C compiler should refuse to compile it.

Actually, that's not quite true. Attempting to initialize a char*
with a char** is a constraint violation. A conforming C compiler must
issue a diagnostic. Once it's done so, it's not required either to
accept or to reject the translation unit.

<OT>I *think* the rules are similar in C++, but I'm too lazy to search
through the C++ standard for the corresponding wording. In any case,
I *think* that Visual C++ can be used as a C compiler.</OT>

--
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.
Sep 25 '06 #9

P: n/a
Keith Thompson wrote:
Ian Collins <ia******@hotmail.comwrites:
>>
A C++ compiler should refuse to compile the line you snipped;

A C compiler should refuse to compile it.

Actually, that's not quite true. Attempting to initialize a char*
with a char** is a constraint violation. A conforming C compiler must
issue a diagnostic. Once it's done so, it's not required either to
accept or to reject the translation unit.

<OT>I *think* the rules are similar in C++, but I'm too lazy to search
through the C++ standard for the corresponding wording. In any case,
I *think* that Visual C++ can be used as a C compiler.</OT>
<OT>In C++, you can't assign or initialise with incompatible types, it's
an error.</OT>

I can't see why C doesn't enforce the same rules, if you want to do an
incompatible assignment, you can force the issue with a cast.

--
Ian Collins.
Sep 25 '06 #10

P: n/a
Ian Collins wrote:
pkirk25 wrote:
>>[snip]
My complier is Visual C++ 6 wcih I know is old but it is what was
available.

I genuinely think my problems are dwon to struggling with indirection
and pointers moret han the compiler, tempting tho it is to blame
Microsoft.

A C++ compiler should refuse to compile the line you snipped;

char *strReturn = &strTmp;

Here you are attempting to initialise a char* with a char**, either use
Oops, I should have written "attempting to initialise a char* with a
pointer to an array of char".

--
Ian Collins.
Sep 25 '06 #11

P: n/a
pkirk25 wrote:
>
.... snip ...
>
I create my variable, pass it to my function, verify that the data
has been passed correctly and then cannot get the data back!

If I change the return to some random string literal, it comes
back fine.

All advice appreciated.

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

char * FixString(char *strIn)
{
char *strMsg = strIn;
char strTmp[40] = "";
char *strReturn = &strTmp;
.... snip ...
>
return strReturn; /* change to return "All clear" and it works fine
*/
You are returning the address of local storage, which storage no
longer exists after the function returns. Change the prototype to
read:

void FixString(const char *strIn, char *strOut, sizet maxout);

and call it with

char *instring = "whatever";
char outstring[SZ]; /* where SZ has been suitably defined */

FixString(instring, outstring, SZ-1);

remembering that the parameters instring and outstring will
automatically be converted to pointers to the first member at the
call. You can use the maxout parameter to protect against buffer
overflow. You can also change the void type to int if you need to
return an error indicator (such as incipient buffer overflow).
--
Some informative links:
<news:news.announce.newusers
<http://www.geocities.com/nnqweb/>
<http://www.catb.org/~esr/faqs/smart-questions.html>
<http://www.caliburn.nl/topposting.html>
<http://www.netmeister.org/news/learn2quote.html>
<http://cfaj.freeshell.org/google/>

Sep 25 '06 #12

P: n/a
On Tue, 26 Sep 2006 10:46:28 +1200, Ian Collins <ia******@hotmail.com>
wrote:
>pkirk25 wrote:
>[snip]
My complier is Visual C++ 6 wcih I know is old but it is what was
available.

I genuinely think my problems are dwon to struggling with indirection
and pointers moret han the compiler, tempting tho it is to blame
Microsoft.
A C++ compiler should refuse to compile the line you snipped;

char *strReturn = &strTmp;

Here you are attempting to initialise a char* with a char**, either use
The advice is correct but the detail is wrong. The statement attempts
to assign a char* with a value of type char(*)[40].
>
char *strReturn = strTmp;

or

char *strReturn = &strTmp[0];
snip
Remove del for email
Sep 26 '06 #13

P: n/a
Ian Collins <ia******@hotmail.comwrites:
Keith Thompson wrote:
>Ian Collins <ia******@hotmail.comwrites:
>>>
A C++ compiler should refuse to compile the line you snipped;

A C compiler should refuse to compile it.

Actually, that's not quite true. Attempting to initialize a char*
with a char** is a constraint violation. A conforming C compiler must
issue a diagnostic. Once it's done so, it's not required either to
accept or to reject the translation unit.

<OT>I *think* the rules are similar in C++, but I'm too lazy to search
through the C++ standard for the corresponding wording. In any case,
I *think* that Visual C++ can be used as a C compiler.</OT>
<OT>In C++, you can't assign or initialise with incompatible types, it's
an error.</OT>

I can't see why C doesn't enforce the same rules, if you want to do an
incompatible assignment, you can force the issue with a cast.
C does enforce the same rules. An assignment between incompatible
types is a constraint violation, requiring a diagnostic.

A C compiler is never required to *reject* a translation unit unless
it contains a "#error" directive. (Many implementation-specific
extensions are implemented by giving meaning to code that would
otherwise violate a constraint.)

--
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.
Sep 26 '06 #14

P: n/a
Barry Schwarz wrote:
On Tue, 26 Sep 2006 10:46:28 +1200, Ian Collins <ia******@hotmail.com>
wrote:

>>pkirk25 wrote:
>>>[snip]
My complier is Visual C++ 6 wcih I know is old but it is what was
available.

I genuinely think my problems are dwon to struggling with indirection
and pointers moret han the compiler, tempting tho it is to blame
Microsoft.

A C++ compiler should refuse to compile the line you snipped;

char *strReturn = &strTmp;

Here you are attempting to initialise a char* with a char**, either use


The advice is correct but the detail is wrong. The statement attempts
to assign a char* with a value of type char(*)[40].
I know, that's why I corrected it.

--
Ian Collins.
Sep 26 '06 #15

P: n/a
Keith Thompson wrote:
Ian Collins <ia******@hotmail.comwrites:
>>Keith Thompson wrote:
>>>Ian Collins <ia******@hotmail.comwrites:

A C++ compiler should refuse to compile the line you snipped;

A C compiler should refuse to compile it.

Actually, that's not quite true. Attempting to initialize a char*
with a char** is a constraint violation. A conforming C compiler must
issue a diagnostic. Once it's done so, it's not required either to
accept or to reject the translation unit.

<OT>I *think* the rules are similar in C++, but I'm too lazy to search
through the C++ standard for the corresponding wording. In any case,
I *think* that Visual C++ can be used as a C compiler.</OT>
<OT>In C++, you can't assign or initialise with incompatible types, it's
an error.</OT>

I can't see why C doesn't enforce the same rules, if you want to do an
incompatible assignment, you can force the issue with a cast.


C does enforce the same rules. An assignment between incompatible
types is a constraint violation, requiring a diagnostic.
Rather feeble enforcement.
A C compiler is never required to *reject* a translation unit unless
it contains a "#error" directive. (Many implementation-specific
extensions are implemented by giving meaning to code that would
otherwise violate a constraint.)
Or contains an expression that isn't well formed. In C++, an assignment
between incompatible types isn't well formed.

--
Ian Collins.
Sep 26 '06 #16

P: n/a
Ian Collins wrote:
Keith Thompson wrote:
A C compiler is never required to *reject* a translation unit unless
it contains a "#error" directive. (Many implementation-specific
extensions are implemented by giving meaning to code that would
otherwise violate a constraint.)
Or contains an expression that isn't well formed.
No. A C compiler is not required to reject a translation unit that
contains an expression that isn't well formed. Keith Thompson's
statement was correct.

Sep 26 '06 #17

P: n/a
pkirk25 said:
"0 error(s), 0 warning(s)"

Well, that means i can go to bed!
No, it means it's time to crank up your warning level.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #18

P: n/a
Hi pkirk25

if you write your FixString function with two pointer-Arguments,
you don't have to make a return call.
char * FixString(char *strIn, char *strOut)
Other Solution:

void FixString(char *strIn, char *strOut)
{
int i = 0;
int j = strlen(strIn);

for (i = 0; i <= j; ++i) {
/* removing the cleanup code for brevity on usenet */
strOut[i] = strIn[i];
}
printf("%s\n", strOut);
}

int main(void)
{
char *strOut = "This is a line from a web page <br>";
int i = strlen(strOut);
char *backBuff = malloc(i);
FixString(strOut, backBuff);

printf("%s\n", backBack); /* Prints out the string
perfectly */

return 0;
}
Sven

Sep 26 '06 #19

P: n/a
sv******@computerscience.ch said:
Hi pkirk25

if you write your FixString function with two pointer-Arguments,
you don't have to make a return call.
>char * FixString(char *strIn, char *strOut)

Other Solution:

void FixString(char *strIn, char *strOut)
{
int i = 0;
int j = strlen(strIn);
Undefined behaviour. Bonus question: why?
for (i = 0; i <= j; ++i) {
/* removing the cleanup code for brevity on usenet */
strOut[i] = strIn[i];
}
printf("%s\n", strOut);
Undefined behaviour. Bonus question: why?
}

int main(void)
{
char *strOut = "This is a line from a web page <br>";
int i = strlen(strOut);
Undefined behaviour. Bonus question: why?
char *backBuff = malloc(i);
Constraint violation. Bonus question: why?
FixString(strOut, backBuff);
Undefined behaviour. Bonus question: why?
>
printf("%s\n", backBack); /* Prints out the string
perfectly */
Undefined behaviour. Bonus question: why?
return 0;
}
At least you got main's return type right.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #20

P: n/a
Hi Richard,

I was not thinking in every detail about the
code pkirk25 posted. The main thing I wanted to say is that the
return in the FixString-function is not needed.

You always write about undefined behavior, I don't know exactly
why but I suggest it is because of the use of unchecked
pointer-variables.

Can you give me the answers to your quetions?
void FixString(char *strIn, char *strOut)
{
int i = 0;
int j = strlen(strIn);

Undefined behaviour. Bonus question: why?
for (i = 0; i <= j; ++i) {
/* removing the cleanup code for brevity on usenet */
strOut[i] = strIn[i];
}
printf("%s\n", strOut);
Undefined behaviour. Bonus question: why?
char *strOut = "This is a line from a web page <br>";
int i = strlen(strOut);
Undefined behaviour. Bonus question: why?
char *backBuff = malloc(i);
Constraint violation. Bonus question: why?
FixString(strOut, backBuff);
Undefined behaviour. Bonus question: why?
printf("%s\n", backBack); /* Prints out the string
perfectly */
Undefined behaviour. Bonus question: why?
At least you got main's return type right.
Thank you :)

Sven

Sep 26 '06 #21

P: n/a
If I understand rightly, the original version needed help in 3 areas:
1. Basic C logic - can't return pointer to local variable
2. C style - working with pointers is often better than working with
function returns
3. Security - what if the input file has a huge mangled string?

This is my effort to fix all three. It works so many thanks.

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

#define STRING_MAX_SIZE 254 /* ample headroom here */

/*
Function that
*/
int FixString(const char *strIn, /* string to fix */
const char cToken, /* token to use */
char *strOut) /* the fixed string */
{
int i = 0;
int j = strlen(strIn);
if (j STRING_MAX_SIZE)
{
printf("Input too big\n");
return 1;
}


for (i = 0; i <= j; ++i)
{
/* The cleanup code */
if (cToken != strIn[i])
{
strOut[i] = strIn[i];
} else
{
/* the token is found */
strOut[i] = '\0'; /* terminates the string */
j = i; /* ends the loop */
}
}

return 0;
}

int main(void)
{
char *strOut = "Moonglade-Alliance<br>";
char cToken = '-';
int i = strlen(strOut);

char *backBuff = malloc(STRING_MAX_SIZE);
int j = FixString(strOut, cToken, backBuff);

if (j 0)
{
printf("Something has gone wrong\n");
return 1;
} else
{
printf("%s\n", backBuff); /* show fixed string */
return 0;
}
}

Sep 26 '06 #22

P: n/a
sv******@computerscience.ch said:
Hi Richard,

I was not thinking in every detail about the
code pkirk25 posted. The main thing I wanted to say is that the
return in the FixString-function is not needed.

You always write about undefined behavior, I don't know exactly
why but I suggest it is because of the use of unchecked
pointer-variables.

Can you give me the answers to your quetions?
1) You don't have a prototype in scope for strlen (which, incidentally, does
*not* return int, so I don't know why you're using an int to catch its
return value), so compiler will not know to supply the required conversion
from size_t to int.

2) You don't have a prototype in scope for printf, which is a variadic
function.

3) See 1)

4) You don't have a prototype in scope for malloc, so the assignment is
illegal and must be diagnosed.

5) You're passing a potentially meaningless pointer to a function that
depends utterly on having a valid pointer to a certain minimum number of
bytes. Incidentally, you didn't allocate enough space for the null
terminator.

6) See 2)
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #23

P: n/a
pkirk25 said:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Huge win, well done.
#define STRING_MAX_SIZE 254 /* ample headroom here */
/*
Function that
*/
int FixString(const char *strIn, /* string to fix */
const char cToken, /* token to use */
char *strOut) /* the fixed string */
{
int i = 0;
int j = strlen(strIn);
size_t would be better. Incidentally, you already measured the length of the
string, in main. Why not pass that length in as an argument, to save
recalculating it? (Measuring a string's length is O(n), so it's not
something you want to repeat if you can avoid it.)
for (i = 0; i <= j; ++i)
If you write to strOut[j], you're in trouble.
{
/* The cleanup code */
if (cToken != strIn[i])
{
strOut[i] = strIn[i];
Here, you write to strOut[j] (last time round the loop).
} else
{
/* the token is found */
strOut[i] = '\0'; /* terminates the string */
Here, too.
int i = strlen(strOut);
Why int? strlen doesn't return int.
>
char *backBuff = malloc(STRING_MAX_SIZE);
i + 1 would have been enough. But you want to check that it worked:

if(backBuff != NULL)
{

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #24

P: n/a
Richard Heathfield wrote:
sv******@computerscience.ch said:
char *backBuff = malloc(i);

Constraint violation. Bonus question: why?
A question: since the behaviour is undefined if you declare any
standard library function (and more) inappropriately, isn't the
compiler allowed to try and generate a proper declaration for malloc(),
and accept this code without any diagnostic?

Sep 26 '06 #25

P: n/a
Harald van D?k said:
Richard Heathfield wrote:
>sv******@computerscience.ch said:
char *backBuff = malloc(i);

Constraint violation. Bonus question: why?

A question: since the behaviour is undefined if you declare any
standard library function (and more) inappropriately, isn't the
compiler allowed to try and generate a proper declaration for malloc(),
and accept this code without any diagnostic?
No, because a diagnostic message *must* be generated if the source code
breaks any syntax rule or violates any constraint - which this one does -
even if the compiler can silently fix the code and proceed with the
translation (which it may, at its discretion). To be totally clear, the
diagnostic message is required. A successful translation (which may or may
not do what the programmer intended) is not required, but is allowed. That
is, the compiler may accept the code, or reject it, and it may either
understand (and thus, presumably, fix) the code or misinterpret it; the
Standard allows any of those options.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #26

P: n/a
Richard Heathfield wrote:
Harald van D?k said:
Richard Heathfield wrote:
sv******@computerscience.ch said:
char *backBuff = malloc(i);

Constraint violation. Bonus question: why?
A question: since the behaviour is undefined if you declare any
standard library function (and more) inappropriately, isn't the
compiler allowed to try and generate a proper declaration for malloc(),
and accept this code without any diagnostic?

No, because a diagnostic message *must* be generated if the source code
breaks any syntax rule or violates any constraint - which this one does -
even if the compiler can silently fix the code and proceed with the
translation (which it may, at its discretion).
I mostly agree, except for the "which this one does" part. I think
you're overlooking my point. I'm not so sure the standard specifies
that any constraint is violated, since the standard does not specify
what the effect of the implicit declaration of malloc() is.

Sep 26 '06 #27

P: n/a
Harald van D?k said:
Richard Heathfield wrote:
>Harald van D?k said:
Richard Heathfield wrote:
sv******@computerscience.ch said:
char *backBuff = malloc(i);

Constraint violation. Bonus question: why?

A question: since the behaviour is undefined if you declare any
standard library function (and more) inappropriately, isn't the
compiler allowed to try and generate a proper declaration for malloc(),
and accept this code without any diagnostic?

No, because a diagnostic message *must* be generated if the source code
breaks any syntax rule or violates any constraint - which this one does -
even if the compiler can silently fix the code and proceed with the
translation (which it may, at its discretion).

I mostly agree, except for the "which this one does" part. I think
you're overlooking my point. I'm not so sure the standard specifies
that any constraint is violated, since the standard does not specify
what the effect of the implicit declaration of malloc() is.
But it does. The (C90) standard requires that, in the absence of an explicit
declaration for a function, that function is treated as if it returned int.
So the compiler is required to treat malloc(i) as returning int (because we
don't have a prototype). This int is then assigned to a char *, and that's
what violates a constraint.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #28

P: n/a
In article <PL******************************@bt.com>,
Richard Heathfield <in*****@invalid.invalidwrote:
>I mostly agree, except for the "which this one does" part. I think
you're overlooking my point. I'm not so sure the standard specifies
that any constraint is violated, since the standard does not specify
what the effect of the implicit declaration of malloc() is.
>But it does. The (C90) standard requires that, in the absence of an explicit
declaration for a function, that function is treated as if it returned int.
So now we have an (implicit) incorrect declaration for a standard
library function, which results in undefined behaviour. Could that
undefined behaviour not include magically using a correct declaration
instead?

-- Richard
Sep 26 '06 #29

P: n/a
Richard Heathfield wrote:
Harald van D?k said:
Richard Heathfield wrote:
Harald van D?k said:

Richard Heathfield wrote:
sv******@computerscience.ch said:
char *backBuff = malloc(i);

Constraint violation. Bonus question: why?

A question: since the behaviour is undefined if you declare any
standard library function (and more) inappropriately, isn't the
compiler allowed to try and generate a proper declaration for malloc(),
and accept this code without any diagnostic?

No, because a diagnostic message *must* be generated if the source code
breaks any syntax rule or violates any constraint - which this one does -
even if the compiler can silently fix the code and proceed with the
translation (which it may, at its discretion).
I mostly agree, except for the "which this one does" part. I think
you're overlooking my point. I'm not so sure the standard specifies
that any constraint is violated, since the standard does not specify
what the effect of the implicit declaration of malloc() is.

But it does. The (C90) standard requires that, in the absence of an explicit
declaration for a function, that function is treated as if it returned int.
And as soon as malloc() is declared as returning int, before malloc()'s
new declaration is used, the behaviour is undefined. Would you also say
a diagnostic is required for

#define IGNORE(x) /* nothing */

int main (void)
{
IGNORE(")
void *p = malloc();
IGNORE(")
}

After all, here too the standard specifies both that the behaviour is
undefined before malloc()'s result is used, and that there would be a
constraint violation if the behaviour weren't explicitly undefined.

Sep 26 '06 #30

P: n/a
Richard Tobin said:
In article <PL******************************@bt.com>,
Richard Heathfield <in*****@invalid.invalidwrote:
>>I mostly agree, except for the "which this one does" part. I think
you're overlooking my point. I'm not so sure the standard specifies
that any constraint is violated, since the standard does not specify
what the effect of the implicit declaration of malloc() is.
>>But it does. The (C90) standard requires that, in the absence of an
explicit declaration for a function, that function is treated as if it
returned int.

So now we have an (implicit) incorrect declaration for a standard
library function, which results in undefined behaviour. Could that
undefined behaviour not include magically using a correct declaration
instead?
Yes (provided the constraint violation is still diagnosed). :-)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #31

P: n/a
Harald van Dijk schrieb:
<snip>
#define IGNORE(x) /* nothing */

int main (void)
{
IGNORE(")
Completely unrelated nit: " is not a valid preprocessing token.
void *p = malloc();
IGNORE(")
}
<snip>

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Sep 26 '06 #32

P: n/a
Harald van D?k said:
Richard Heathfield wrote:
<snip>
>The (C90) standard requires that, in the absence of an
explicit declaration for a function, that function is treated as if it
returned int.

And as soon as malloc() is declared as returning int, before malloc()'s
new declaration is used, the behaviour is undefined.
C&V, please.
Would you also say a diagnostic is required for

#define IGNORE(x) /* nothing */

int main (void)
{
IGNORE(")
void *p = malloc();
IGNORE(")
}
I don't understand this code. I would have expected it to pre-process to:

int main (void)
{

void *p = malloc();

}

but in fact cpp pre-processed it to:

int main (void)
{

}

Why?

Assuming gcc is correct, the C source code doesn't ever see the malloc, so
the point is moot.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #33

P: n/a
Richard Heathfield wrote:
Harald van D?k said:
Richard Heathfield wrote:

<snip>
The (C90) standard requires that, in the absence of an
explicit declaration for a function, that function is treated as if it
returned int.
And as soon as malloc() is declared as returning int, before malloc()'s
new declaration is used, the behaviour is undefined.

C&V, please.
In C99, it's 7.1.3p2.
"No other identifiers are reserved. If the program declares or
defines an identifier in a
context in which it is reserved (other than as allowed by 7.1.4), or
defines a reserved
identifier as a macro name, the behavior is undefined."
I know C89 has similar wording, but I don't know the C&V.
Would you also say a diagnostic is required for

#define IGNORE(x) /* nothing */

int main (void)
{
IGNORE(")
void *p = malloc();
IGNORE(")
}

I don't understand this code. I would have expected it to pre-process to:

int main (void)
{

void *p = malloc();

}

but in fact cpp pre-processed it to:

int main (void)
{

}

Why?
As far as the standard is concerned, the tokens before preprocessing
are

[#] [define] [IGNORE] [(] [x] [)]

[int] [main] [(] [void] [)]
[{]
[IGNORE] [(] ["] [)]
[void][*] [p] [=] [malloc] [(] [)] [;]
[IGNORE] [(] ["] [)]
[}]

And the behaviour is undefined per 6.4p3. Because the behaviour is
undefined, compilers are permitted to support multi-line string
literals as an extension, and what gcc makes of it is

[#] [define] [IGNORE] [(] [x] [)]

[int] [main] [(] [void] [)]
[{]
[IGNORE] [(] [")\n\
void *p = malloc();\n\
IGNORE("] [)]
[}]

Sep 26 '06 #34

P: n/a
[non-ASCII symbols removed or replaced]

Harald van D?k said:
Richard Heathfield wrote:
>Harald van D?k said:
Richard Heathfield wrote:

<snip>
>The (C90) standard requires that, in the absence of an
explicit declaration for a function, that function is treated as if it
returned int.

And as soon as malloc() is declared as returning int, before malloc()'s
new declaration is used, the behaviour is undefined.

C&V, please.

In C99, it's 7.1.3p2.
"No other identifiers are reserved. If the program declares or
defines an identifier in a
context in which it is reserved (other than as allowed by 7.1.4), or
defines a reserved
identifier as a macro name, the behavior is undefined."
I know C89 has similar wording, but I don't know the C&V.
It's 4.1.2:

"If the program defines an external identifier with the same name as a
reserved external identifier, even in a semantically equivalent form, the
behavior is undefined."

So the whole thing has been re-worded in C99, and we have become divided by
a common language. My argument is based on C90, where it remains valid,
because malloc(i) is not a definition of malloc.
Would you also say a diagnostic is required for

#define IGNORE(x) /* nothing */

int main (void)
{
IGNORE(")
void *p = malloc();
IGNORE(")
}

I don't understand this code.
<snip>
As far as the standard is concerned, the tokens before preprocessing
....do not legally include ". Very clever. :-)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #35

P: n/a
Richard Heathfield wrote:
[non-ASCII symbols removed or replaced]
Sorry, that's what kpdf does when I simply copy and paste.
Harald van D?k said:
Richard Heathfield wrote:
Harald van D?k said:

Richard Heathfield wrote:

<snip>

The (C90) standard requires that, in the absence of an
explicit declaration for a function, that function is treated as if it
returned int.

And as soon as malloc() is declared as returning int, before malloc()'s
new declaration is used, the behaviour is undefined.

C&V, please.
In C99, it's 7.1.3p2.
"No other identifiers are reserved. If the program declares or
defines an identifier in a
context in which it is reserved (other than as allowed by 7.1.4), or
defines a reserved
identifier as a macro name, the behavior is undefined."
I know C89 has similar wording, but I don't know the C&V.

It's 4.1.2:

"If the program defines an external identifier with the same name as a
reserved external identifier, even in a semantically equivalent form, the
behavior is undefined."

So the whole thing has been re-worded in C99, and we have become divided by
a common language. My argument is based on C90, where it remains valid,
because malloc(i) is not a definition of malloc.
Odd and interesting. It may also be addressed by C99's 6.2.7p2; is this
in C90?
"All declarations that refer to the same object or function shall have
compatible type;
otherwise, the behavior is undefined."

Sep 26 '06 #36

P: n/a
pkirk25 wrote:
#define STRING_MAX_SIZE 254 /* ample headroom here */

/*
Function that
*/
You may be truncating for Usenet, but I consider the function header
to be one of the most important parts of my code. It is the contract
that I meet, a reference point to determine if a problem is incorrect
function implementation or incorrect usage. My suggestion is to take
advantage of that opportunity.
int FixString(const char *strIn, /* string to fix */
const char cToken, /* token to use */
char *strOut) /* the fixed string */
{
int i = 0;
int j = strlen(strIn);
if (j STRING_MAX_SIZE)
{
printf("Input too big\n");
return 1;
}
While this works, my suggestion is since the maximum string length limit
is determined by the size of the array passed to strOut, the caller
should specify the length to the function, not code an arbitrary length
between the function and its caller. If a size parameter is needed, it
could be added as an additional parameter. In this case, it might be
better to have the caller verify that the input string is not longer
than the output string and stipulate that as an input requirement to use
the function.

Also, if an error is detected in a function, I prefer to pass an error
code to the caller and let the caller print an error message if
suitable. This makes the function more generic and able to work in
different environments where printf output may not be suitable. Also,
the caller has more context about the error to be able to give more
useful information. For example, in the case, strIn is simply a pointer
to a string, which could be used for many different things. The caller
should know what the string is used for, which might be a file name.
Therefore the caller might issue a message to stderr that the output
file name is too long.

--
Thad
Sep 26 '06 #37

P: n/a
Harald van Dijk said:
Richard Heathfield wrote:
<snip>
>>
So the whole thing has been re-worded in C99, and we have become divided
by a common language. My argument is based on C90, where it remains
valid, because malloc(i) is not a definition of malloc.

Odd and interesting. It may also be addressed by C99's 6.2.7p2; is this
in C90?
"All declarations that refer to the same object or function shall have
compatible type;
otherwise, the behavior is undefined."
It is [3.1.2.6], but in the absence of <stdlib.hthere is no prior
declaration for malloc, so it doesn't apply here.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #38

P: n/a
"pkirk25" <pa*****@kirks.netwrites:
#define STRING_MAX_SIZE 254 /* ample headroom here */

int FixString(const char *strIn, /* string to fix */
const char cToken, /* token to use */
char *strOut) /* the fixed string */
{
int i = 0;
int j = strlen(strIn);
if (j STRING_MAX_SIZE)
{
printf("Input too big\n");
return 1;
}
Personally, I would change the function to accept the length of the
strOut buffer instead of gicing a fixed value, like, so:

#v+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void strnfix(const char *strIn, char cToken, char *strOut, size_t len) {
if (!len) return;
while (--len && *strIn && *strIn != cToken) {
*strOut++ = *strIn++;
}
*strOut = 0;
}

int main(void) {
char *string = "Moonglade-Alliance<br>";
char *buffer = malloc(256);
if (!buffer) {
puts("not enough memory");
return 1;
}
strnfix(string, '-', buffer, 256);
puts(buffer);
return 0;
}
#v-

BTW. The function can also by written using strrchr(), strncpy() and
memcpy().

--
Best regards, _ _
.o. | Liege of Serenly Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michal "mina86" Nazarewicz (o o)
ooo +--<mina86*tlen.pl>--<jid:mina86*jabber.org>--ooO--(_)--Ooo--
Sep 26 '06 #39

P: n/a
Richard Heathfield wrote:
Harald van Dijk said:
Richard Heathfield wrote:

<snip>
>
So the whole thing has been re-worded in C99, and we have become divided
by a common language. My argument is based on C90, where it remains
valid, because malloc(i) is not a definition of malloc.
Odd and interesting. It may also be addressed by C99's 6.2.7p2; is this
in C90?
"All declarations that refer to the same object or function shall have
compatible type;
otherwise, the behavior is undefined."

It is [3.1.2.6], but in the absence of <stdlib.hthere is no prior
declaration for malloc, so it doesn't apply here.
I'm not sure what you mean. One possibility is that you're mixing up
6.2.7p2 with 6.7p4 ("All declarations in the same scope that refer to
the same object or function shall specify compatible types."). The
latter does not apply, but the former applies even to declarations in
different translation units. The other possibility is that you're
saying the (C90) standard requires implementations to act as if the
standard library is not written in C.

Sep 26 '06 #40

P: n/a
Harald van D?k said:
Richard Heathfield wrote:
>Harald van Dijk said:
Richard Heathfield wrote:

<snip>
>>
So the whole thing has been re-worded in C99, and we have become
divided by a common language. My argument is based on C90, where it
remains valid, because malloc(i) is not a definition of malloc.

Odd and interesting. It may also be addressed by C99's 6.2.7p2; is this
in C90?
"All declarations that refer to the same object or function shall have
compatible type;
otherwise, the behavior is undefined."

It is [3.1.2.6], but in the absence of <stdlib.hthere is no prior
declaration for malloc, so it doesn't apply here.

I'm not sure what you mean. One possibility is that you're mixing up
6.2.7p2 with 6.7p4 ("All declarations in the same scope that refer to
the same object or function shall specify compatible types.").
Nope.
The
latter does not apply, but the former applies even to declarations in
different translation units.
A different translation unit is a completely different kettle of bananas.
It's compiled separately, and the compiler has no way of knowing what
declarations exist within Translation Unit A, at the time it is compiling
Translation Unit B. It may not even be the same compiler that was used for
compiling Translation Unit A. So it's hard to see how Translation Unit A's
contents can be relevant to whether a diagnostic message is required when
compiling Translation Unit B.
The other possibility is that you're
saying the (C90) standard requires implementations to act as if the
standard library is not written in C.
No, I'm not saying that at all.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #41

P: n/a
Richard Heathfield wrote:
Harald van D?k said:
Richard Heathfield wrote:
Harald van Dijk said:
Richard Heathfield wrote:

<snip>
So the whole thing has been re-worded in C99, and we have become
divided by a common language. My argument is based on C90, where it
remains valid, because malloc(i) is not a definition of malloc.

Odd and interesting. It may also be addressed by C99's 6.2.7p2; is this
in C90?
"All declarations that refer to the same object or function shall have
compatible type;
otherwise, the behavior is undefined."

It is [3.1.2.6], but in the absence of <stdlib.hthere is no prior
declaration for malloc, so it doesn't apply here.
I'm not sure what you mean. One possibility is that you're mixing up
6.2.7p2 with 6.7p4 ("All declarations in the same scope that refer to
the same object or function shall specify compatible types.").

Nope.
The
latter does not apply, but the former applies even to declarations in
different translation units.

A different translation unit is a completely different kettle of bananas.
It's compiled separately, and the compiler has no way of knowing what
declarations exist within Translation Unit A, at the time it is compiling
Translation Unit B. It may not even be the same compiler that was used for
compiling Translation Unit A. So it's hard to see how Translation Unit A's
contents can be relevant to whether a diagnostic message is required when
compiling Translation Unit B.
That's why it's not a constraint violation, just plain undefined
behaviour. No diagnostic required (but permitted as always).

Sep 26 '06 #42

P: n/a
Ian Collins wrote:
A C++ compiler should refuse to compile the line you snipped;
C++ compilers are off-topic here. A C compiler must emit a diagnostic
but need not refuse to compile.
char *strReturn = &strTmp;

Here you are attempting to initialise a char* with a char**, either use
It's actually a char(*)[40].
char *strReturn = strTmp;

or

char *strReturn = &strTmp[0];
Good advice.
Add an extra parameter:

char* FixString( const char* strIn, char* strOut )

Note the change of strIn to const, you aren't changing it in your
function. Use strOut where you use strTmp.

You can then call it with:

const char *strOut = "This is a line from a web page <br>"

char *backBuff = char[someSize];
That's a syntax error. Perhaps you meant
char backBuff[someSize];
or
char *backBuff = (char[someSize]){0};
or
char *backBuff = malloc(someSize);

Unless someSize is not a macro for a constant literal integer (in which
case it should have been written in all caps), C99 is required for the
first one as it is a variable length array. C99 is definitely required
for the second one as it uses a compound literal (possibly of a VLA
type). The third form will work in C89.
>
char *strBack = FixString(strOut, backBuff);
--
Simon.
Sep 26 '06 #43

P: n/a

"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:xr******************************@bt.com...
pkirk25 said:
>#include <stdio.h>
#include <string.h>
#include <stdlib.h>

Huge win, well done.
>#define STRING_MAX_SIZE 254 /* ample headroom here */
/*
Function that
*/
int FixString(const char *strIn, /* string to fix */
const char cToken, /* token to use */
char *strOut) /* the fixed string */
{
int i = 0;
int j = strlen(strIn);

size_t would be better. Incidentally, you already measured the length of
the
string, in main. Why not pass that length in as an argument, to save
recalculating it? (Measuring a string's length is O(n), so it's not
something you want to repeat if you can avoid it.)
>for (i = 0; i <= j; ++i)

Why bother with computing the length at all?
You can just as easily do something like:
char *c= strIn;
j=0;
while (*c) {
if ( j == STRING_MAX_SIZE-1 ) {
strOut[j] = '\0';
break; /* Or set j to an error code first? */
}
if ( cToken == *c) {
strOut[j] = '\0';
break;
}
strOut[j++] = *(c++);
}
return j;
>
If you write to strOut[j], you're in trouble.
>{
/* The cleanup code */
if (cToken != strIn[i])
{
strOut[i] = strIn[i];

Here, you write to strOut[j] (last time round the loop).
>} else
{
/* the token is found */
strOut[i] = '\0'; /* terminates the string */

Here, too.
>int i = strlen(strOut);

Why int? strlen doesn't return int.
>>
char *backBuff = malloc(STRING_MAX_SIZE);

i + 1 would have been enough. But you want to check that it worked:

if(backBuff != NULL)
{

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
--
Fred L. Kleinschmidt
Boeing Associate Technical Fellow
Technical Architect, Software Reuse Project
Sep 26 '06 #44

P: n/a
Harald van Dijk said:

[I said]
>for compiling Translation Unit A. So it's hard to see how Translation
Unit A's contents can be relevant to whether a diagnostic message is
required when compiling Translation Unit B.

That's why it's not a constraint violation, just plain undefined
behaviour. No diagnostic required (but permitted as always).
I am delighted to announce that I have now completely lost the plot on this
thread. You have managed to spin me around and around sufficiently often
that I am quite dizzy, and I have no idea whether you are right or I am.

Fortunately for me, I don't particularly care (if you'll forgive me for
saying so - I assure you it's nothing personal), since what we are
discussing is code that we both agree is fundamentally broken, and our
dispute is only concerned with how the compiler is required/allowed to
react to it. Yes, academically it is interesting, and anyone who cares
enough will no doubt take up the argument if they disagree sufficiently
with you - but I have decided to adopt a position of "Just Don't Do That,
and the issue disappears." :-)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 26 '06 #45

P: n/a
Richard Heathfield wrote:
Harald van Dijk said:

[I said]
for compiling Translation Unit A. So it's hard to see how Translation
Unit A's contents can be relevant to whether a diagnostic message is
required when compiling Translation Unit B.
That's why it's not a constraint violation, just plain undefined
behaviour. No diagnostic required (but permitted as always).

I am delighted to announce that I have now completely lost the plot on this
thread. You have managed to spin me around and around sufficiently often
that I am quite dizzy, and I have no idea whether you are right or I am.

Fortunately for me, I don't particularly care (if you'll forgive me for
saying so - I assure you it's nothing personal), since what we are
discussing is code that we both agree is fundamentally broken, and our
dispute is only concerned with how the compiler is required/allowed to
react to it. Yes, academically it is interesting, and anyone who cares
enough will no doubt take up the argument if they disagree sufficiently
with you - but I have decided to adopt a position of "Just Don't Do That,
and the issue disappears." :-)
I have no problems with that. And regardless of whether a diagnostic is
required, I can agree that an implementation /should/ generate one.

Sep 26 '06 #46

P: n/a
On Tue, 2006-26-09 at 14:58 +0000, Fred Kleinschmidt wrote:
*(c++)
What does this evaluate to? (Specifically, if the postfix operator is
within parentheses, does it evaluate to the old value of c or the new
one?)

--
Andrew Poelstra <http://www.wpsoftware.net/projects/>

Sep 26 '06 #47

P: n/a
Andrew Poelstra wrote:
On Tue, 2006-26-09 at 14:58 +0000, Fred Kleinschmidt wrote:
>>*(c++)

What does this evaluate to? (Specifically, if the postfix operator is
within parentheses, does it evaluate to the old value of c or the new
one?)
The old one. The parentheses do not change the value.s

--
Thad
Sep 26 '06 #48

This discussion thread is closed

Replies have been disabled for this discussion.