473,394 Members | 1,802 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

Something wrong in my program

Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm trying
to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns some
strange values...

Here's my code (please pardon the mess):

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

int main(void){
char *trimbegin(char *text);
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);
char buffer[size + 1];
char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){
buffer[j] = text[i];
j++;
ok = 1;
}
}
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
return ptr;
}

And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?

Thanks for all your help!

-Dom

Nov 14 '05 #1
60 3255
"Dominique Léger" <dl****@vif.com> wrote in message
news:10***************@www.vif.com...
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm trying to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns some strange values...

Here's my code (please pardon the mess):

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

int main(void){
char *trimbegin(char *text);
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);
char buffer[size + 1];
char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){
buffer[j] = text[i];
j++;
ok = 1;
}
}
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
return ptr;
}

And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?

Thanks for all your help!

-Dom
Hello, guess you forgot to add a zero terminator to the string.

From the code, it would be something like: buffer[j] = 0 just right before
the printf() statement.
int size = strlen(text);
char buffer[size + 1];

I wonder how is this accepted by a C compiler?

--
Elias
Nov 14 '05 #2
Dominique Léger <dl****@vif.com> spoke thus:
char *trimbegin(char *text){
char buffer[size + 1];
char *ptr;
/* intervening code trimmed */
ptr = buffer;
return ptr; ^^^^^^^^^^ returns the address of buffer! (clc nitpicks
on that statement welcome!) }


Surprisingly (at least to you ;)), this is all the code you need to
see what's going wrong. You are returning the address of an automatic
variable, and when trimbegin returns, the memory that was reserved for
buffer (and that ptr pointed to, and that you returned a pointer to)
is freed. Thus, that memory is no longer guaranteed to be good for
anything, and you should not use it. If you did something like

ptr=malloc( strlen(buffer)+1 ); /* sizeof( char ) guaranteed to be 1 */
strcpy( ptr, buffer );
return ptr;

you'd be fine.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #3
Christopher Benson-Manica <at***@nospam.cyberspace.org> scribbled the following:
Dominique Léger <dl****@vif.com> spoke thus:
char *trimbegin(char *text){
char buffer[size + 1];
char *ptr;
/* intervening code trimmed */
ptr = buffer;
return ptr;

^^^^^^^^^^ returns the address of buffer! (clc nitpicks
on that statement welcome!)


Actually it returns the address of a char, which corresponds to the
exact same machine-level address as the address of buffer. The only
difference between them is the type.
}


--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"It's not survival of the fattest, it's survival of the fittest."
- Ludvig von Drake
Nov 14 '05 #4
Christopher Benson-Manica <at***@nospam.cyberspace.org> spoke thus:
If you did something like
(blah)
you'd be fine.


Well, that and listened (probably) to a previous poster who wondered why you
were able to compile

char buffer[size+1]; /* dynamic size arrays are C99, yes? */

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #5
Dominique Léger <dl****@vif.com> wrote:
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm trying
to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns some
strange values...

Here's my code (please pardon the mess):

#include <stdio.h>
#include <string.h>
#include <ctype.h> /* for isspace */
int main(void){
char *trimbegin(char *text); Function prototypes shouldn't be buried in function definitions,
IMO. Move the prototype outside main, or define trimbegin before
main.
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);
char buffer[size + 1];
char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){
buffer[j] = text[i];
j++;
ok = 1;
}
}
That's a very complicated way to do the job at hand.
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
Obfuscation is not a cure for undefined behaviour... ;-)
return ptr;
... which you invoke here by returning an invalid address, since
buffer will be gone when control reaches end of function.
Either
- qualify buffer static (rendering the function non-reentrant
and making C99 VLAs impossible to use), or
- provide a second parameter and let the caller provide the
buffer, or
- dynamically allocate memory for buffer in the function and
document that the caller has to free the memory if it's no
longer needed, or
- return only a pointer to the first non-whitespace character
in the original string,
whatever fits your needs best.

The last one is particularly easy to implement:

char *skipspace( char *s )
{
while ( isspace( *s ) )
s++;
return s;
}
}

And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?


You were lucky, because you invoked undefined behaviour, didn't
get what you expected (indicating that something's wrong) and
nothing really serious happened.

HTH

Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.eskimo.com/~scs/C-faq/top.html
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html

Nov 14 '05 #6
Dominique Léger wrote:
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm trying
to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns some
strange values...

Here's my code (please pardon the mess):

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

int main(void){
char *trimbegin(char *text);
Move the function definition above the main(), and you won't have to
declare its prototype here.
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text); should be a size_t, not an int.
char buffer[size + 1]; gcc -Wall -ansi -pedantic :
warning: ISO C89 forbids variable-size array `buffer'

char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){ gcc -Wall -ansi -pedantic :
warning: implicit declaration of function `isspace'
buffer[j] = text[i];
j++;
ok = 1;
}
}
Are you sure your algorithm is ok and as simple as it could be ?
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
return ptr;
Which can be shortened to :
return &buffer[0];
and further to :
return buffer;

in which case you've got an additionnal, and very annoying warning :

gcc -Wall -ansi -pedantic :
warning: function returns address of local variable
}
You understand that, even if the value returned is an effective memory
address, what becomes of the memory block starting at this address is no
more under your control as soon as the function returns ? This memory
may be reclaimed and reused by the system at any time, so trying to read
at this at address may have any unpredictable result - not talking about
*writing* at this address.
And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?


First you forgot to copy the terminating '\0' to buffer, so buffer is
char array, but not a string. In C, a string is a char array *terminated
by the char '\0'*. Note that this character is *not* counted by
strlen(), since it's not part of the string, but merely a 'sentinel'
indicating where the string ends (the 'effective' string may be shorter
than the memory block it is contained in).

Then, you return the address of a local automatic variable, which
invokes UB (Undefined Behavior) as soon as you read or write at this
address. Anything can happen, even that it *seems* to work correctly.

Solutions are :
- either dynamically allocate memory for buffer in trimbegin(), or
declare buffer outside trimbegin() and pass its address to trimbegin
(for now you'd better try the second solution)
- make sure that buffer terminates with a '\0' (the simplest way to do
it being to copy the terminating '\0' of the source string)
- eventually rewrite your algorithm to make it simpler

tip 1 : you dont need any test in the for loop body nor the ok flag
tip 2 : the for loop syntax is :
for (<initialisation>;<test>;<on_each_iteration>)
{
<body>
}
where any of <initialisation>, <test>, <on_each_iteration>, and
<body> can be empty.
Feel free to post amended code for review !-)

HTH
Bruno

Nov 14 '05 #7
Hi,

"Dominique Léger" <dl****@vif.com> a écrit dans le message de news:
10***************@www.vif.com...
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm trying to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns some strange values...

Here's my code (please pardon the mess):

#include <stdio.h>
#include <string.h>
#include <ctype.h> /* for isspace()*/
int main(void){
char *trimbegin(char *text);
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);
char buffer[size + 1];
VLA in C99 only
char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){
buffer[j] = text[i];
j++;
ok = 1;
}
}
I'm not sure about your algorithm, since ok is initialized to 0 and that
isspace() returns a non-zero value if it is a white-space character.
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
return ptr;
}

And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?
Thanks for all your help!

-Dom


I suggest you my example :

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

char* trim(char* s);

int main()
{
char * str = " \tHello World";
char * trimmed;
printf("Original :\n%s\n",str);
trimmed = trim(str);
printf("Trimmed :\n%s\n",trimmed);
free(trimmed);
}

char* trim(char* s)
{
char * res;
int cnt = 0;
int cnt2 = 0;

while (isspace(s[cnt]) != 0)
cnt++;

res = (char*)malloc(sizeof(char)*(strlen(s)-cnt+1));

while (s[cnt] != '\0')
res[cnt2++] = s[cnt++];

res[cnt2] = '\0';

return &res[0];
}

Best regards. régis
Nov 14 '05 #8
"Régis Troadec" <re**@wanadoo.fr> spoke thus:
int main()
{
char * str = " \tHello World";
char * trimmed;
printf("Original :\n%s\n",str);
trimmed = trim(str);
printf("Trimmed :\n%s\n",trimmed); /* What will happen if trim fails (returns NULL)? Of course,
it never does so at the moment, but if it were coded
correctly it might... */ free(trimmed);
} char* trim(char* s)
{
char * res;
int cnt = 0;
int cnt2 = 0;
while (isspace(s[cnt]) != 0)
cnt++;
res = (char*)malloc(sizeof(char)*(strlen(s)-cnt+1)); /* There are numerous reasons why casting the return value of
malloc() is inadvisable, although I will let others
enumerate them */
/* And of course, what if malloc() fails? */ while (s[cnt] != '\0')
res[cnt2++] = s[cnt++];
res[cnt2] = '\0';
return &res[0]; /* res===&res[0], so why obfuscate? */ }


I don't claim that all is well otherwise, but those are what my
untrained eyes see.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.

(Ignore blank lines following - need to keep tin happy)



Nov 14 '05 #9
Régis Troadec wrote:
Hi,

"Dominique Léger" <dl****@vif.com> a écrit dans le message de news:
10***************@www.vif.com...
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm
trying
to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns


some
strange values...

Here's my code (please pardon the mess):

(snip OP code)
I suggest you my example :
I suggest the small corrections below...
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* trim(char* s);

int main() int main(void) or int main(int argc, char **argv) {
char * str = " \tHello World";
char * trimmed;
printf("Original :\n%s\n",str);
trimmed = trim(str);
printf("Trimmed :\n%s\n",trimmed);
free(trimmed);
}

char* trim(char* s)
{
char * res;
int cnt = 0;
int cnt2 = 0;

while (isspace(s[cnt]) != 0)
cnt++;

res = (char*)malloc(sizeof(char)*(strlen(s)-cnt+1)); res = malloc(strlen(s) - cnt + 1);
if (res != NULL) /* malloc may fail */
{ while (s[cnt] != '\0')
res[cnt2++] = s[cnt++];

res[cnt2] = '\0'; }
else {
/* whatever */
} return &res[0]; return res; }


HTH
Bruno

Nov 14 '05 #10
"lallous" <la*****@lgwm.org> wrote:
"Dominique Léger" <dl****@vif.com> wrote: <snip>
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"? <snip>Hello, guess you forgot to add a zero terminator to the string.
This was my first thought too, but the OP apparently /did/ copy
the terminating null character. *But* the OP invoked UB by
returning the address to automatic storage, and that's why...
[...] buffer[j] = 0 just right before the printf() statement.


.... won't help.
int size = strlen(text);
char buffer[size + 1];

I wonder how is this accepted by a C compiler?


C99 VLA.

Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.eskimo.com/~scs/C-faq/top.html
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html

Nov 14 '05 #11
Bruno Desthuilliers <bd***********@tsoin-tsoin.free.fr> wrote:
Dominique Léger wrote: <snip>
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"

<snip>First you forgot to copy the terminating '\0' to buffer, so buffer is
char array, but not a string.

<snip>

Even if it were the case, it would not explain the differences
between the two lines of output, re-quoted above.

Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.eskimo.com/~scs/C-faq/top.html
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html

Nov 14 '05 #12
in comp.lang.c i read:
char buffer[size+1]; /* dynamic size arrays are C99, yes? */


yes, though it is called a variable length array.

--
a signature
Nov 14 '05 #13
Dominique Léger <dl****@vif.com> wrote in message news:<10***************@www.vif.com>...
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm trying
to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns some
strange values...
General comment: Consider turning on some more warnings on your
compiler. I see the following with
gcc -pedantic -Wall -W -std=c89 -o foo foo.c
foo.c:15: warning: ISO C89 forbids variable-size array `buffer'
foo.c:27: warning: implicit declaration of function `isspace'
The first may not bother you, the second shows failure to include
a needed header...

Here's my code (please pardon the mess):

#include <stdio.h>
#include <string.h>
#include <ctype.h> /* for isspace */

int main(void){
It is more usual to put your function declarations at file scope rather
than inside a function. And you might consider declaring the function
to be "static", the proper course to take for functions that are not
being used outside the current source file.
char *trimbegin(char *text);
You want const char *str here, to indicate this must not
be modified. This lets the compiler help you out by
pointing out any attempt to change this.
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

You want const char *text as the argument, to indicate it is
not to be modified.
char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);
The array size below is not a constant expression. That is OK in
C99 and as a compiler extension sometimes (it obviously works on
your compiler). Just FYI, it doesn't work on strict C89 compilers.
char buffer[size + 1];
char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
What is below seems to me to work just fine. But if you want to
write it a different and slightly simpler way, consider using a
loop to advance a pointer past the whitespace and then use a
strcpy to copy the rest.
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){
buffer[j] = text[i];
j++;
ok = 1;
}
}
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
You are returning a pointer to "automatic" storage. This is a big
no-no. I believe (no standard handy) that this causes "undefined
behavior". What happens to the memory once you leave the scope at
which the storage is allocated, you don't know what is going to
happen to it. Thankfully, in your case, something bad DOES happen
so you know there is a problem. You either need to declare the
buffer array "static" (often a bad idea in larger programs, fine
here), or allocate some memory dynamically using malloc and free
it later.
return ptr;
}

And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?

Thanks for all your help!

-Dom

Nov 14 '05 #14
Irrwahn Grausewitz wrote:
Bruno Desthuilliers <bd***********@tsoin-tsoin.free.fr> wrote:
Dominique Léger wrote:


<snip>
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"


<snip>
First you forgot to copy the terminating '\0' to buffer, so buffer
is char array, but not a string.


<snip>

Even if it were the case, it would not explain the differences
between the two lines of output, re-quoted above.


With all this foofaraw, nobody seems to point out that all trim
requires (for leading blanks) is:

const char *trim(const char *s)
{
while ((' ' == *s) || ('\t' == *s)) s++;
return s;
}

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #15
in comp.lang.c i read:
With all this foofaraw, nobody seems to point out that all trim
requires (for leading blanks) is:

const char *trim(const char *s)
{
while ((' ' == *s) || ('\t' == *s)) s++;


isspace() may be better to use, as it is locale sensitive. then again some
may dislike that carriage control, line termination, and vertical white-
space are also included.

--
a signature
Nov 14 '05 #16
Régis Troadec wrote:
Hi,

"Dominique Léger" <dl****@vif.com> a écrit dans le message de news:
10***************@www.vif.com...
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm
trying
to do is a simple function that trims spaces & tabs at the beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns


some
strange values...

Here's my code (please pardon the mess):

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

#include <ctype.h> /* for isspace()*/

int main(void){
char *trimbegin(char *text);
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);
char buffer[size + 1];

VLA in C99 only

char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){
buffer[j] = text[i];
j++;
ok = 1;
}
}

I'm not sure about your algorithm, since ok is initialized to 0 and that
isspace() returns a non-zero value if it is a white-space character.

printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
return ptr;
}

And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?
Thanks for all your help!

-Dom

I suggest you my example :

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

char* trim(char* s);

int main()
{
char * str = " \tHello World";
char * trimmed;
printf("Original :\n%s\n",str);
trimmed = trim(str);
printf("Trimmed :\n%s\n",trimmed);
free(trimmed);

exit(EXIT_SUCCESS); /* 0 is fine, too */
/* or you could have return 0; just as well */ }

char* trim(char* s)
{
char * res;
int cnt = 0;
int cnt2 = 0;

while (isspace(s[cnt]) != 0)
cnt++;

res = (char*)malloc(sizeof(char)*(strlen(s)-cnt+1)); Not testing the return value of malloc() is VERY bad, because if
malloc() returns NULL you will attempt to access memory you don't own.
Which is a source of undefined behavior. Which means your program, OS,
and hardware can literally do /anything/ after that point.

It is important enough that even trivial code should test for a failure,
and some coders (myself included) have created a version of malloc that
will quit the program with an error message instead of returning NULL.
(That can be deeply stupid in some cases, which is why I only use it in
the cases where it makes sense.)

Casting the retval of malloc() is bad:
1. Can hide a failure to #include <stdlib.h> because if a prototype is
not in scope, malloc() implicitly returns an int. This can be dangerous
on some machines.
2. Makes code harder to change later, when you decide to make malloc()
allocate something besides a buffer of char.
3. Demonstrates a lack of knowledge about how a pointer to void works.
4. Introduces unneeded visual clutter.

sizeof(char) is unneeded, as sizeof(char) == 1 by definition.

while (s[cnt] != '\0')
res[cnt2++] = s[cnt++];

res[cnt2] = '\0';

return &res[0];
Why not just return res; ?
}


--
My address is yvoregnevna gjragl-guerr gjb-gubhfnaq guerr ng lnubb qbg pbz
Note: Rot13 and convert spelled-out numbers to numerical equivalents.
Nov 14 '05 #17
those who know me have no need of my name wrote:
in comp.lang.c i read:

char buffer[size+1]; /* dynamic size arrays are C99, yes? */

yes, though it is called a variable length array.


What happens if you try to use a VLA to allocate more memory than your
OS will let your program have?

--
My address is yvoregnevna gjragl-guerr gjb-gubhfnaq guerr ng lnubb qbg pbz
Note: Rot13 and convert spelled-out numbers to numerical equivalents.
Nov 14 '05 #18
Irrwahn Grausewitz wrote:
Bruno Desthuilliers <bd***********@tsoin-tsoin.free.fr> wrote:
Dominique Léger wrote:


<snip>
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"


<snip>
First you forgot to copy the terminating '\0' to buffer, so buffer is
char array, but not a string.


<snip>

Even if it were the case, it would not explain the differences
between the two lines of output, re-quoted above.

Regards


That was the second point, that you may have noticed if you had read
further !-)

Regards too

Nov 14 '05 #19
CBFalconer wrote:
(snip)
With all this foofaraw, nobody seems to point out that all trim
requires (for leading blanks) is:

const char *trim(const char *s)
{
while ((' ' == *s) || ('\t' == *s)) s++;
return s;
}


Some did notice, but tried to lead the OP to discover this by himself
instead of giving him the solution.

Nov 14 '05 #20

I'm sorry to post such programming misbehaviours,
but it drives me to ask two questions...See below

"August Derleth" <se*@sig.now> a écrit dans le message de news:
ky***************@fe02.usenetserver.com...
Régis Troadec wrote:

I suggest you my example :

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

char* trim(char* s);

int main()
{
char * str = " \tHello World";
char * trimmed;
printf("Original :\n%s\n",str);
trimmed = trim(str);
printf("Trimmed :\n%s\n",trimmed);
free(trimmed); exit(EXIT_SUCCESS); /* 0 is fine, too */
/* or you could have return 0; just as well */
}
ugghhh...I forgot to return

char* trim(char* s)
{
char * res;
int cnt = 0;
int cnt2 = 0;

while (isspace(s[cnt]) != 0)
cnt++;

res = (char*)malloc(sizeof(char)*(strlen(s)-cnt+1));

Not testing the return value of malloc() is VERY bad, because if
malloc() returns NULL you will attempt to access memory you don't own.
Which is a source of undefined behavior. Which means your program, OS,
and hardware can literally do /anything/ after that point.

It is important enough that even trivial code should test for a failure,
and some coders (myself included) have created a version of malloc that
will quit the program with an error message instead of returning NULL.
(That can be deeply stupid in some cases, which is why I only use it in
the cases where it makes sense.)


Shame on me, I'll provide much more safe-code next time.
I don't always think to test the retval of malloc
in trivial programs ...I've surely acquired this bad practice by programming
at school

Casting the retval of malloc() is bad:
1. Can hide a failure to #include <stdlib.h> because if a prototype is
not in scope, malloc() implicitly returns an int. This can be dangerous
on some machines.
2. Makes code harder to change later, when you decide to make malloc()
allocate something besides a buffer of char.
3. Demonstrates a lack of knowledge about how a pointer to void works.
4. Introduces unneeded visual clutter.

2 questions :

1. I've heard that explicit conversion from void* to the type of lvalue
was sometimes necessary for portability because the adresses of used types
could
have different formats on the target system, is it true ?
2. I read the FAQ (7.7), and another explanation (surely good) is given :
casting malloc() was required before ANSI/ISO introduced the void* pointer,
only to silence warnings of assignements. Is it the only reason ?
sizeof(char) is unneeded, as sizeof(char) == 1 by definition.


while (s[cnt] != '\0')
res[cnt2++] = s[cnt++];

res[cnt2] = '\0';

return &res[0];


Why not just return res; ?


I find &tab[i] quite easy to understand and interpret as the "i-th element
adress"

Best regards, régis
Nov 14 '05 #21
CBFalconer <cb********@yahoo.com> wrote:
Irrwahn Grausewitz wrote:
Bruno Desthuilliers <bd***********@tsoin-tsoin.free.fr> wrote:
>Dominique Léger wrote:


<snip>
>> What the result is supposed to be: "Hello World!"
>> What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"


<snip>
>First you forgot to copy the terminating '\0' to buffer, so buffer
> is char array, but not a string.


<snip>

Even if it were the case, it would not explain the differences
between the two lines of output, re-quoted above.


With all this foofaraw, nobody seems to point out that all trim
requires (for leading blanks) is:

const char *trim(const char *s)
{
while ((' ' == *s) || ('\t' == *s)) s++;
return s;
}


You must've missed my first reply to the OP upthread
(ID: lh********************************@4ax.com), which
contained the following code snippet:

IG: #include <ctype.h>
IG: [...]
IG: char *skipspace( char *s )
IG: {
IG: while ( isspace( *s ) )
IG: s++;
IG: return s;
IG: }

However, some notes:

- I admit that throwing in some const qualifiers at appropriate
places would be an improvement.

- In C99 isblank() could be used instead of isspace(), which
would make the code behave like your version, modulo locale
specifics, which are accounted for by isblank() but not by
your code.

Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.eskimo.com/~scs/C-faq/top.html
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html

Nov 14 '05 #22
In article <news:EA***************@fe02.usenetserver.com>
August Derleth <se*@sig.now> writes:
What happens if you try to use a VLA to allocate more memory than your
OS will let your program have?


The Standard does not say.

Several "real world" systems rudely terminate your program with a
SIGILL, often subsequently reported as an "Illegal instruction".
This is rather misleading, as the actual machine instructions
involved were entirely legal ("subtract N from stack pointer") --
it was the resulting stack overflow that was problematic. :-) A
termination message of the form "this program tried to use more
memory than you instructed me to allow it" would be considerably
nicer.

(On at least some of these systems, you can arrange to catch
SIGILL signals on an alternate stack, and do something about it.
Or, of course, you can just use malloc() instead of VLAs, but
then you should free() the memory when you are done with it.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #23
On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Régis Troadec"
<re**@wanadoo.fr> wrote:
2 questions :

1. I've heard that explicit conversion from void* to the type of lvalue
was sometimes necessary for portability because the adresses of used types
could have different formats on the target system, is it true ?
In C. this is never true - void* converts implicitly to any other
pointer type. C++ is different.
2. I read the FAQ (7.7), and another explanation (surely good) is given :
casting malloc() was required before ANSI/ISO introduced the void* pointer,
only to silence warnings of assignements. Is it the only reason ?


Yes, in C. The other reason often given is that C++ needs the casts,
so if you are a C++ programmer you get used to them. This is a bad
reason - its like not using the clutch in a manual gearbox because you
habitually drive an automatic. It may be harmless but....
> return &res[0];


Why not just return res; ?


I find &tab[i] quite easy to understand and interpret as the "i-th element
adress"


Sure, for you and me, with our decades of experience. But you don't
write code for /your/ ease of understanding, you write it for the
maintenance programmer who comes after you. This maintainer may be a
junior programmer, and you need to make it easy for them. So use the
simplest expression that is correct.

In this case, returning the address of the 0-th element merely
obfuscates the code and makes maintenance harder.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 14 '05 #24
Bruno Desthuilliers wrote:
Dominique Léger wrote:
Hello guys,

I'm kinda new to C, and I'm having a hard time with strings. What I'm
trying to do is a simple function that trims spaces & tabs at the
beginning of a
given string. For example, I want this: " Hello World" to become this:
"Hello World". At first glance, my function seems to work, but returns
some strange values...

Here's my code (please pardon the mess):

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

int main(void){
char *trimbegin(char *text);


Move the function definition above the main(), and you won't have to
declare its prototype here.
char *str = " Hello World!";
char *result = trimbegin(str);
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trimbegin(char *text){
int i = 0, j = 0, ok = 0;
int size = strlen(text);

should be a size_t, not an int.
char buffer[size + 1];

gcc -Wall -ansi -pedantic :
warning: ISO C89 forbids variable-size array `buffer'

char *ptr;

printf("Original text is: \"%s\"\n", text);
printf("That's %d characters long...\n", size);
printf("Now, our text buffer can contain %d characters\n", size +
1);
for (i = 0; i <= size; i++){
if (ok == 1){
buffer[j] = text[i];
j++;
}
else if (isspace(text[i]) == 0 && ok == 0){

gcc -Wall -ansi -pedantic :
warning: implicit declaration of function `isspace'
buffer[j] = text[i];
j++;
ok = 1;
}
}


Are you sure your algorithm is ok and as simple as it could be ?
printf("What the result is supposed to be: \"%s\"\n", buffer);
ptr = buffer;
return ptr;


Which can be shortened to :
return &buffer[0];
and further to :
return buffer;

in which case you've got an additionnal, and very annoying warning :

gcc -Wall -ansi -pedantic :
warning: function returns address of local variable
}


You understand that, even if the value returned is an effective memory
address, what becomes of the memory block starting at this address is no
more under your control as soon as the function returns ? This memory
may be reclaimed and reused by the system at any time, so trying to read
at this at address may have any unpredictable result - not talking about
*writing* at this address.
And here's the output:

[dom@localhost C]$ ./a.out
Original text is: " Hello World!"
That's 14 characters long...
Now, our text buffer can contain 15 characters
What the result is supposed to be: "Hello World!"
What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
World!"?


First you forgot to copy the terminating '\0' to buffer, so buffer is
char array, but not a string. In C, a string is a char array *terminated
by the char '\0'*. Note that this character is *not* counted by
strlen(), since it's not part of the string, but merely a 'sentinel'
indicating where the string ends (the 'effective' string may be shorter
than the memory block it is contained in).

Then, you return the address of a local automatic variable, which
invokes UB (Undefined Behavior) as soon as you read or write at this
address. Anything can happen, even that it *seems* to work correctly.

Solutions are :
- either dynamically allocate memory for buffer in trimbegin(), or
declare buffer outside trimbegin() and pass its address to trimbegin
(for now you'd better try the second solution)
- make sure that buffer terminates with a '\0' (the simplest way to do
it being to copy the terminating '\0' of the source string)
- eventually rewrite your algorithm to make it simpler

tip 1 : you dont need any test in the for loop body nor the ok flag
tip 2 : the for loop syntax is :
for (<initialisation>;<test>;<on_each_iteration>)
{
<body>
}
where any of <initialisation>, <test>, <on_each_iteration>, and
<body> can be empty.
Feel free to post amended code for review !-)

HTH
Bruno


Here's the amended code:

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

char *trim(const char *text);
int main(void){
char *result = trim(" Hello World!");
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trim(const char *text){
int i = 0;
static char buffer[20];
while( isspace(text[i]) ) i++;
strcpy(buffer, &text[i]);
printf("What the result is supposed to be: \"%s\"\n", buffer);
return buffer;
}

A little better, isn't it? :-) However, dynamically allocating memory for
'buffer' would definitely be more interesting. I'll try to figure it out on
my own and post the results later...

I have one last question: Everybody here seems to despise the new standard,
C99. Why is that so?

-Dom

Nov 14 '05 #25
Dominique Léger wrote:
big snip... I have one last question: Everybody here seems to despise the new standard,
C99. Why is that so?

I don't think you are gauging opinion on this accurately. While opinions
differ, I think that most people here would agree that C99 has a number
of nice improvements over C89, such as

- introduction of the "restrict" keyword
- locally declared-and-scoped loop variables
- introduction of >= 64-bit ints, and boolean/complex types

Most would probably also agree that '//' type comments should not have
been introduced, but that's another matter :)

Unfortunately, C99 compilers are few and far between; e.g. the GNU C
compiler supports only a subset of the new features. Basically if you
need to write code that must be portable to multiple compilers /
platforms, C89 is the way to go at this point.

One thing that raises my eyebrows once in a while when following the
traffic here, is that the "standards thumpers" usually quote
chapter-and-verse from the C99 standard (this seems to be the consensus
on the 'de jure' standard), while code snippets using new C99 features
usually elicit snide comments - C89 is preferred as the 'de facto'
standard. The latter is perhaps not in small part because C99 code can
look a lot like C++ code :-)
Best regards,

Sidney

Nov 14 '05 #26
August Derleth wrote:
those who know me have no need of my name wrote:

.... snip ...

yes, though it is called a variable length array.


What happens if you try to use a VLA to allocate more memory than
your OS will let your program have?


I would expect about the same reaction as to a stack overflow. If
the OS can't simply allocate more stack the program normally goes
boom.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #27
those who know me have no need of my name wrote:
With all this foofaraw, nobody seems to point out that all trim
requires (for leading blanks) is:

const char *trim(const char *s)
{
while ((' ' == *s) || ('\t' == *s)) s++;


isspace() may be better to use, as it is locale sensitive. then
again some may dislike that carriage control, line termination,
and vertical white-space are also included.


And if I had used it I would have needed to mention some includes,
complicate with casts to unsigned char, etc. to fend off the
ravening hordes of c.l.c nitpickers. I would also have had to
point out the above isspace failings, and the routine would have
been performing calls to isspace, and thus probably be less
efficient. I suspect blanks and tabs are precisely what the OP
wanted to skip, so I said so.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #28
Sidney Cadot wrote:
Dominique Léger wrote:
big snip...

I have one last question: Everybody here seems to despise the
new standard, C99. Why is that so?


I don't think you are gauging opinion on this accurately. While
opinions differ, I think that most people here would agree that
C99 has a number of nice improvements over C89, such as


In addition the C99 standard is readily available, while the C89
standard is not. So far, if one adheres to C89 the result is
usually C99 valid, but not the reverse. Once GCC becomes fully
C99 compliant, and people built suitable libraries, I think the
rush will begin.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #29
CBFalconer wrote:
August Derleth wrote:
those who know me have no need of my name wrote:


... snip ...
yes, though it is called a variable length array.


What happens if you try to use a VLA to allocate more memory than
your OS will let your program have?

I would expect about the same reaction as to a stack overflow. If
the OS can't simply allocate more stack the program normally goes
boom.


Eh, ugly. Very ugly.

Between what you and Chris Torek wrote, I'd rather use malloc(): At
least the library function gives me some chance to respond to an error,
even if I need to keep track of my malloc()-free() pairs.

But I wasn't on the C99 committee, and I don't have a Real C99 Compiler
anyway. ;)

--
My address is yvoregnevna gjragl-guerr gjb-gubhfnaq guerr ng lnubb qbg pbz
Note: Rot13 and convert spelled-out numbers to numerical equivalents.
Nov 14 '05 #30
Irrwahn Grausewitz <ir*******@freenet.de> wrote:
<snip>
(ID: lh********************************@4ax.com) <snip>IG: while ( isspace( *s ) )
IG: s++;

<snip>

D'oh! I wonder why no-one objected to the missing cast
to unsigned char; will I ever get this right?!?
Well, at least the code matches the subject line... :)

Regards
--
Irrwahn Grausewitz (ir*******@freenet.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.eskimo.com/~scs/C-faq/top.html
acllc-c++ faq : http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html

Nov 14 '05 #31
Dominique Léger wrote:
Bruno Desthuilliers wrote:

(snip)

Feel free to post amended code for review !-)

Here's the amended code:

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

char *trim(const char *text);
int main(void){
char *result = trim(" Hello World!");
printf("What the function returns: \"%s\"\n", result);
return 0;
}

char *trim(const char *text){
int i = 0;
static char buffer[20];
while( isspace(text[i]) ) i++;
strcpy(buffer, &text[i]);


woops ! What happens if buffer is too small ?
printf("What the result is supposed to be: \"%s\"\n", buffer);
return buffer;
}

A little better, isn't it? :-)
I see you've carefully read the other answers !-)
But now you have a big security hole in your code (strcpy to a
fixed-size char array), and the code is not thread-safe (static char array).
However, dynamically allocating memory for
'buffer' would definitely be more interesting.
As a learning exercise, certainly. As a practical solution, I'm not sure
this is the better thing to do...
I'll try to figure it out on
my own and post the results later...

I have one last question: Everybody here seems to despise the new standard,
C99. Why is that so?


It's more a matter of C99-compliant compilers availability than 'despise'.

Bruno

Nov 14 '05 #32
In article <L6****************@fe02.usenetserver.com>, se*@sig.now says...
Eh, ugly. Very ugly.

Between what you and Chris Torek wrote, I'd rather use malloc(): At
least the library function gives me some chance to respond to an error,
even if I need to keep track of my malloc()-free() pairs.


I agree. VLA's don't really provide anything you can't have otherwise
with a lot less downside risk of demon invoking.

--
Randy Howard
2reply remove FOOBAR

Nov 14 '05 #33

Thank you for the answers.

"Mark McIntyre" <ma**********@spamcop.net> a écrit dans le message de news:
dv********************************@4ax.com...
On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Régis Troadec"
<re**@wanadoo.fr> wrote:
2 questions :

1. I've heard that explicit conversion from void* to the type of lvalue
was sometimes necessary for portability because the adresses of used types
could have different formats on the target system, is it true ?
In C. this is never true - void* converts implicitly to any other
pointer type. C++ is different.
2. I read the FAQ (7.7), and another explanation (surely good) is given :
casting malloc() was required before ANSI/ISO introduced the void* pointer,only to silence warnings of assignements. Is it the only reason ?


Yes, in C. The other reason often given is that C++ needs the casts,
so if you are a C++ programmer you get used to them. This is a bad
reason - its like not using the clutch in a manual gearbox because you
habitually drive an automatic. It may be harmless but....
return &res[0];

Why not just return res; ?


I find &tab[i] quite easy to understand and interpret as the "i-th elementadress"


Sure, for you and me, with our decades of experience. But you don't
write code for /your/ ease of understanding, you write it for the
maintenance programmer who comes after you. This maintainer may be a
junior programmer, and you need to make it easy for them. So use the
simplest expression that is correct.

In this case, returning the address of the 0-th element merely
obfuscates the code and makes maintenance harder.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet

News==---- http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups ---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption

=---
Nov 14 '05 #34
Mark McIntyre wrote:
On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
<re**@wanadoo.fr> wrote:
2 questions :

1. I've heard that explicit conversion from void* to the type of lvalue
was sometimes necessary for portability because the adresses of used types
could have different formats on the target system, is it true ?


In C. this is never true - void* converts implicitly to any other
pointer type.


But not without possible loss of information when used with function pointer
types. Caution is indicated.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #35
Richard Heathfield wrote:

Mark McIntyre wrote:
On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
<re**@wanadoo.fr> wrote:
2 questions :

1. I've heard that explicit conversion from void* to the type of lvalue
was sometimes necessary for portability because the adresses of used types
could have different formats on the target system, is it true ?


In C. this is never true - void* converts implicitly to any other
pointer type.


But not without possible loss of information
when used with function pointer types. Caution is indicated.


void* doesn't point to functions.
What do you mean ?

--
pete
Nov 14 '05 #36
pete wrote:
Richard Heathfield wrote:

Mark McIntyre wrote:
> On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
> <re**@wanadoo.fr> wrote:
>
>>2 questions :
>>
>>1. I've heard that explicit conversion from void* to the type of lvalue
>>was sometimes necessary for portability because the adresses of used
>>types
>>could have different formats on the target system, is it true ?
>
> In C. this is never true - void* converts implicitly to any other
> pointer type.


But not without possible loss of information
when used with function pointer types. Caution is indicated.


void* doesn't point to functions.
What do you mean ?


I mean that it's not safe to point void * to functions. Since function
pointers are certainly of pointer type, the statement "void* converts
implicitly to *any other* pointer type" is a dangerous one IMHO.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #37
Richard Heathfield wrote:

pete wrote:
Richard Heathfield wrote:

Mark McIntyre wrote:

> On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
> <re**@wanadoo.fr> wrote:
>
>>2 questions :
>>
>>1. I've heard that explicit conversion from void* to the type of lvalue
>>was sometimes necessary for portability because the adresses of used
>>types
>>could have different formats on the target system, is it true ?
>
> In C. this is never true - void* converts implicitly to any other
> pointer type.

But not without possible loss of information
when used with function pointer types. Caution is indicated.


void* doesn't point to functions.
What do you mean ?


I mean that it's not safe to point void * to functions. Since function
pointers are certainly of pointer type, the statement "void* converts
implicitly to *any other* pointer type" is a dangerous one IMHO.


You're talking about "possible loss of information"
I thought it was undefined behavior and a constraint violation.

--
pete
Nov 14 '05 #38

On Sun, 18 Jan 2004, pete wrote:

Richard Heathfield wrote:
pete wrote:
Richard Heathfield wrote:
> Mark McIntyre wrote:
> >
> > In C. this is never true - void* converts implicitly to any other
> > pointer type.
>
> But not without possible loss of information
> when used with function pointer types. Caution is indicated.

void* doesn't point to functions.
What do you mean ?


I mean that it's not safe to point void * to functions. Since function
pointers are certainly of pointer type, the statement "void* converts
implicitly to *any other* pointer type" is a dangerous one IMHO.


You're talking about "possible loss of information"
I thought it was undefined behavior and a constraint violation.


I think pete is right. I suggest the use of the term 'object pointer',
as contrasted with 'function pointer' -- a void* MAY safely be converted
to any other OBJECT POINTER type, as far as I'm aware.

-Arthur

Nov 14 '05 #39
pete wrote:
Richard Heathfield wrote:

pete wrote:
> Richard Heathfield wrote:
>>
>> Mark McIntyre wrote:
>>
>> > On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
>> > <re**@wanadoo.fr> wrote:
>> >
>> >>2 questions :
>> >>
>> >>1. I've heard that explicit conversion from void* to the type of
>> >>lvalue was sometimes necessary for portability because the adresses
>> >>of used types
>> >>could have different formats on the target system, is it true ?
>> >
>> > In C. this is never true - void* converts implicitly to any other
>> > pointer type.
>>
>> But not without possible loss of information
>> when used with function pointer types. Caution is indicated.
>
> void* doesn't point to functions.
> What do you mean ?
I mean that it's not safe to point void * to functions. Since function
pointers are certainly of pointer type, the statement "void* converts
implicitly to *any other* pointer type" is a dangerous one IMHO.


You're talking about "possible loss of information"


Yes.
I thought it was undefined behavior and a constraint violation.


It is certainly undefined behaviour (I wrongly assumed that this would be
obvious from the fact that a loss of information is involved - a rather
drastic thing where a function address is concerned!). But I can't find a
constraint that it violates, but that doesn't mean there isn't one. Do you
have a reference?

Of course, allowing it is a common extension (see informative Annex J). If
it /is/ a constraint violation, then clearly a diagnostic is required. If
not, then it is possible that a newbie might fall into this trap unawares,
so I still think it was worth pointing out the issue.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #40
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:dv********************************@4ax.com...
... void* converts implicitly to any other pointer type.


That's not true in the case of function pointers. Apart from null pointers,
the conversion in such cases is undefined. [C99 J.5.7 notwithstanding.]

--
Peter
Nov 14 '05 #41
"Randy Howard" <ra**********@FOOmegapathdslBAR.net> wrote in message
news:MP************************@news.megapathdsl.n et...
In article <L6****************@fe02.usenetserver.com>, se*@sig.now says...
Eh, ugly. Very ugly.

Between what you and Chris Torek wrote, I'd rather use malloc(): At
least the library function gives me some chance to respond to an error,
even if I need to keep track of my malloc()-free() pairs.


I agree. VLA's don't really provide anything you can't have otherwise
with a lot less downside risk of demon invoking.


I don't see risk management issue.

Over-allocation via VLA is no different to over-allocation via any other
automatic object.

Many development tools can diagnose the level of stack usage by a program,
and most programmers will specify the appropriate stack level settings
within the final executable.

Something as simple as...

void blah(size_t parameter)
{
if (parameter <= 20000)
{
char buffer[parameter];
/* ... */
}
else
/* fail */
}

....is probably safer and more robust than...

void blah(size_t parameter)
{
char buffer[20000];
/* ... */
}

Even with malloc, you're still faced with the issue of what to do if the
allocation fails. And worse, on some systems, a non-void malloc return need
not indicate successful allocation of resources!

You're screwed either way. You might as well use the cleaner faster syntax
of VLA's than cumbersome malloc/free pointers, if it's convenient to do so!

--
Peter
Nov 14 '05 #42
Richard Heathfield wrote:

pete wrote:
Richard Heathfield wrote:

pete wrote:

> Richard Heathfield wrote:
>>
>> Mark McIntyre wrote:
>>
>> > On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
>> > <re**@wanadoo.fr> wrote:
>> >
>> >>2 questions :
>> >>
>> >>1. I've heard that explicit conversion from void* to the type of
>> >>lvalue was sometimes necessary for portability because the adresses
>> >>of used types
>> >>could have different formats on the target system, is it true ?
>> >
>> > In C. this is never true - void*
>> > converts implicitly to any other pointer type.
>>
>> But not without possible loss of information
>> when used with function pointer types. Caution is indicated.
>
> void* doesn't point to functions.
> What do you mean ?

I mean that it's not safe to point void * to functions.
Since function
pointers are certainly of pointer type,
the statement "void* converts
implicitly to *any other* pointer type" is a dangerous one IMHO.
You're talking about "possible loss of information"


Yes.
I thought it was undefined behavior and a constraint violation.


It is certainly undefined behaviour
(I wrongly assumed that this would be
obvious from the fact that a loss of information is involved - a
rather drastic thing where a function address is concerned!).


Since some pointers are guaranteed to have
the same representation and some are not,
I assume that there may be other information
besides address information, in some pointers.
But I can't find a constraint that it violates,
but that doesn't mean there isn't one. Do you have a reference?


N869
6.5.16 Assignment operators
6.5.16.1 Simple assignment
Constraints
[#1] One of the following shall hold:

-- the left operand has qualified or unqualified
arithmetic type and the right has arithmetic type;
-- the left operand has a qualified or unqualified version
of a structure or union type compatible with the type
of the right;
-- both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to
by the left has all the qualifiers of the type pointed
to by the right;
-- one operand is a pointer to an object or incomplete
type and the other is a pointer to a qualified or
unqualified version of void, and the type pointed to by
the left has all the qualifiers of the type pointed to
by the right; or
-- the left operand is a pointer and the right is a null
pointer constant.
-- the left operand has type _Bool and the right is a
pointer.

--
pete
Nov 14 '05 #43
pete wrote:

Richard Heathfield wrote:

pete wrote:
Richard Heathfield wrote:
>
> pete wrote:
>
> > Richard Heathfield wrote:
> >>
> >> Mark McIntyre wrote:
> >>
> >> > On Fri, 16 Jan 2004 19:40:28 +0100, in comp.lang.c , "Regis Troadec"
> >> > <re**@wanadoo.fr> wrote:
> >> >
> >> >>2 questions :
> >> >>
> >> >>1. I've heard that explicit conversion from void* to the type of
> >> >>lvalue was sometimes necessary for portability because the adresses
> >> >>of used types
> >> >>could have different formats on the target system, is it true ?
> >> >
> >> > In C. this is never true - void*
> >> > converts implicitly to any other pointer type.
> >>
> >> But not without possible loss of information
> >> when used with function pointer types. Caution is indicated.
> >
> > void* doesn't point to functions.
> > What do you mean ?
>
> I mean that it's not safe to point void * to functions.
> Since function
> pointers are certainly of pointer type,
> the statement "void* converts
> implicitly to *any other* pointer type" is a dangerous one IMHO.

You're talking about "possible loss of information"


Yes.
I thought it was undefined behavior and a constraint violation.
But I can't find a constraint that it violates,
but that doesn't mean there isn't one. Do you have a reference?


N869
6.5.16 Assignment operators
6.5.16.1 Simple assignment


The other method of conversion, a cast to (void*),
may only operate on scaler types.

--
pete
Nov 14 '05 #44
<snip>

I wrote:
But I can't find a constraint that it violates,
but that doesn't mean there isn't one. Do you have a reference?

pete wrote:
N869
6.5.16 Assignment operators
6.5.16.1 Simple assignment
Constraints
[#1] One of the following shall hold:


<snip>

Thank you.
--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #45
On Sun, 18 Jan 2004 20:15:55 +1100, in comp.lang.c , "Peter Nilsson"
<ai***@acay.com.au> wrote:
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:dv********************************@4ax.com.. .
... void* converts implicitly to any other pointer type.


That's not true in the case of function pointers


Correct. However its rare that a newby works with function pointers,
and by the time they do, the meaning of void* should hopefully be well
embedded.
Also the OP talks about types.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 14 '05 #46
On Sun, 18 Jan 2004 21:02:35 +1100, "Peter Nilsson"
<ai***@acay.com.au> wrote:
Even with malloc, you're still faced with the issue of what to do if the
allocation fails. And worse, on some systems, a non-void malloc return need
not indicate successful allocation of resources!


Could you expand please. Since malloc always returns a void*, did you
mean non-NULL? Is there a situation where a non-NULL return could
result when the memory requested is not allocated?
<<Remove the del for email>>
Nov 14 '05 #47
Mark McIntyre wrote:

On Sun, 18 Jan 2004 20:15:55 +1100, in comp.lang.c , "Peter Nilsson"
<ai***@acay.com.au> wrote:
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:dv********************************@4ax.com.. .
... void* converts implicitly to any other pointer type.


That's not true in the case of function pointers


Correct. However its rare that a newby works with function pointers,
and by the time they do, the meaning of void* should hopefully be well
embedded.
Also the OP talks about types.


Types apply to functions as well as to objects.

--
pete
Nov 14 '05 #48
Barry Schwarz wrote:
"Peter Nilsson" <ai***@acay.com.au> wrote:
Even with malloc, you're still faced with the issue of what to
do if the allocation fails. And worse, on some systems, a
non-void malloc return need not indicate successful allocation
of resources!


Could you expand please. Since malloc always returns a void*,
did you mean non-NULL? Is there a situation where a non-NULL
return could result when the memory requested is not allocated?


I think he did. In theory a non-NULL return always means the
memory is allocated and usable, however some virtual memory
systems have the annoying habit of allocating virtual memory using
copy on write paging techniques, which means that unexpected
failures can (not will) occur later on use. This is an OS
problem, not a C language problem. Besides which, running into
such an occurence is rare.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #49
Barry Schwarz <sc******@deloz.net> writes:
On Sun, 18 Jan 2004 21:02:35 +1100, "Peter Nilsson"
<ai***@acay.com.au> wrote:
Even with malloc, you're still faced with the issue of what to do if the
allocation fails. And worse, on some systems, a non-void malloc return need
not indicate successful allocation of resources!


Could you expand please. Since malloc always returns a void*, did you
mean non-NULL? Is there a situation where a non-NULL return could
result when the memory requested is not allocated?


I think some malloc() implementations may return a pointer to virtual
memory that isn't actually allocated until it's referenced. If there
isn't actually enough memory (virtual or otherwise) to satisfy the
request, the program can die when it tries to access the memory that
it thinks is already allocated.

Such implementations are probaby non-conforming.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://www.sdsc.edu/~kst>
Schroedinger does Shakespeare: "To be *and* not to be"
Nov 14 '05 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Luka Milkovic | last post by:
Hello, I have a little problem and although it's little it's extremely difficult for me to describe it, but I'll try. I have written a program which extracts certain portions of my received...
5
by: titan0111 | last post by:
#include<iostream> #include<iomanip> #include<cstring> #include<fstream> using namespace std; class snowfall { private: int ft;
5
by: clusardi2k | last post by:
Hello, I have a assignment just thrown onto my desk. What is the easiest way to solve it? Below is a brief description of the task. There are multible programs which use the same library...
4
by: Robert | last post by:
something wrong in wx I wrote program training na Artificial Neural Network. It work well in console mode, but when I try to add GUI there is an error: FANN Error 10: Error reading info from...
10
by: MLH | last post by:
I am concerned. I have recently moved to A97 from Access 2.0 where I rolled out runtime apps with the ADT. Now, the Office Pro Developer's Edition with Access 97 is what I'm using. I find some...
0
by: Protoman | last post by:
I wrote a DHM key exchange program that has something funky going on: the number that you have to send to your friend is completely wrong, but the session key it generates is correct. Wha? Code:...
3
by: Peter Oliphant | last post by:
It's not necessary, but it would be nice if there was a way I could easily create something like a 'web browser form' or a 'display web page form' as forms in my application (in a Panel would be...
13
blazedaces
by: blazedaces | last post by:
Hey guys, how's it going today? So basically I have a program that uses hotbits (a real online random number generator based off radioactive decay) to produce truly random alphanumeric codes (Note:...
34
by: raphfrk | last post by:
This program should copy one file onto the other. It works if I compile it with gcc to a cygwin program. However, if I compile it with the -mno-cygwin option, it doesn't work (this targets native...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.