================================
char RandomChar()
{
return (char)((rand() % 78) + 30);
}
int main()
{
char str[81];
int i, j;
srand(time());
for ( i = 0; i < 10; ++i )
{
str[i] = RandomChar();
printf("%c", str[i] );
}
printf ("\n");
str[10] = '\0';
puts(str);
for ( j = 0; j < 10; ++j ) {
printf("%c", str[j] );
}
printf("%s\n", str);
return 0;
}
> The last 2 printf & puts are not working - any fixes pls:
There are a few things that need to be fixed about the program but the
puts and printf calls look fine.
> ================================
You should #include stdio.h, stdlib.h and time.h.
> char RandomChar()
char RandomChar(void)
is better in C.
> {
> return (char)((rand() % 78) + 30);
> }
>
>
> int main()
Ditto int main(void).
> {
> char str[81];
> int i, j;
>
> srand(time());
This is wrong. time needs to be passed a time_t * argument. If you
don't want to use the facility, pass NULL instead:
srand(time(NULL));
> for ( i = 0; i < 10; ++i )
> {
> str[i] = RandomChar();
> printf("%c", str[i] );
> }
> printf ("\n");
>
>
> str[10] = '\0';
>
> puts(str);
> for ( j = 0; j < 10; ++j ) {
> printf("%c", str[j] );
> }
> printf("%s\n", str);
>
> return 0;
> }
Good layout really helps. Pick style and stick with it (until
someone persuades you there is a better style).
--
Ben.
Better:
char RandomChar() {
static char src[] = "acbdefghijklmnopqrstuvwxyz";
return src[rand() % sizeof src];
}
It's still not terribly random, but it's portable outside of
ASCII systems, is clearer, and will be much easier to extend
if you want to add capitals or numerals to it.
>
>
> int main()
> {
> char str[81];
Where does 81 come from?
> int i, j;
>
> srand(time());
This should be time(NULL) and you should have #include'd
time.h. These are related bugs. Turn up the warning level
on your compiler.
>
> for ( i = 0; i < 10; ++i )
> {
> str[i] = RandomChar();
> printf("%c", str[i] );
> }
> printf ("\n");
>
>
> str[10] = '\0';
10 should probably be a named constant using const or #define.
You use it three times in this short program and changing it
will be a hassle otherwise. (With a +1, you could also use it
in place of the 81 above.)
>
> puts(str);
> for ( j = 0; j < 10; ++j ) {
> printf("%c", str[j] );
> }
> printf("%s\n", str);
You forgot to NULL-terminate it this time. str[10] will still
be 0 from the last call, but it's dangerous and unclear to rely
on such things.
>
> return 0;
> }
>
HTH. Unless I'm missing something, your misuse of time() was
the only serious problem with the code that might be causing
printf() and puts() to fail. But it was a big one, because
time() wants an argument, /and/ it returns a time_t, not an
int as your compiler assumes in the absense of time.h.
For starters, you don't include any headers that declare,
let alone prototype some of the functions you use. It is
necessary to include a prototype for variadic functions
like printf.
> char RandomChar()
> {
> return (char)((rand() % 78) + 30);
You seem to be presuming a character set where these
character codes are printable.
> }
>
> int main()
> {
> char str[81];
> int i, j;
>
> srand(time());
time() takes a pointer to time_t parameter. NULL will suffice.
[There are technical issues relating to converting a time_t
to unsigned, but it's unlikely that time will return a
floating point value outside the range of unsigned int.]
> for ( i = 0; i < 10; ++i )
> {
> str[i] = RandomChar();
> printf("%c", str[i] );
> }
> printf ("\n");
>
> str[10] = '\0';
>
> puts(str);
> for ( j = 0; j < 10; ++j ) {
> printf("%c", str[j] );}
>
> printf("%s\n", str);
>
> return 0;
> }
Fix the issues I mention and the program should 'work', although
the last line will show the string twice because there is no
newline between them.
--
Peter
> On 2010-02-04, 2005 <FW3...@sbcglobal.net> wrote:
>>
>> The last 2 printf & puts are not working - any fixes pls:
>>
>>================================
>>
>> char RandomChar()
>> {
>> return (char)((rand() % 78) + 30);
>> }
>
> Better:
> char RandomChar() {
> static char src[] = "acbdefghijklmnopqrstuvwxyz";
> return src[rand() % sizeof src];
> }
>
> It's still not terribly random, but it's portable outside of
> ASCII systems, is clearer, and will be much easier to extend
> if you want to add capitals or numerals to it.
I doubt you want exactly this. You probably want to use
rand() % (sizeof src - 1)
as the index since returning the null character will give confusing
strings.
>> int main()
>> {
>> char str[81];
>
> Where does 81 come from?
>
>> int i, j;
>>
>> srand(time());
>
> This should be time(NULL) and you should have #include'd
> time.h. These are related bugs. Turn up the warning level
> on your compiler.
>
>>
>> for ( i = 0; i < 10; ++i )
>> {
>> str[i] = RandomChar();
>> printf("%c", str[i] );
>> }
>> printf ("\n");
>>
>>
>> str[10] = '\0';
>
> 10 should probably be a named constant using const or #define.
> You use it three times in this short program and changing it
> will be a hassle otherwise. (With a +1, you could also use it
> in place of the 81 above.)
>
>>
>> puts(str);
>> for ( j = 0; j < 10; ++j ) {
>> printf("%c", str[j] );
>> }
>> printf("%s\n", str);
>
> You forgot to NULL-terminate it this time.
No need. This loop simply prints the characters. I suspect the OP is
trying to see what is happening by printing str in three different
ways.
<snip>
--
Ben.
Ben, Andrew & Peter:
Thanks a bunch,
srand(time(NULL)) actually resolved the issue! {I can't imagine, why
this would cause issue on printf, puts!
I was using codepad.org - it runs w/o "include" - not sure why yet.
Thanks also for the style and other issues - Now the code runs, I will
focus on those as well.
Oh my goodness! I did mean that, and I have been bitten
by this bug in my own code. (Though in that case, it was
a one-off password generator and as I recall I just kept
running it until I got a string without any \0 characters
truncating the string.)
If you call a function without a visible prototype and pass it the
wrong size or type of arguments, the behavior is undefined; anything
could happen. (When I ran your program on my machine, I got a
segmentation fault on the time() call.)
> I was using codepad.org - it runs w/o "include" - not sure why yet.
In C90, you can call a function even if there's no visible declaration
for it. The compiler effectively creates an implicit declaration,
assuming that the function takes whatever arguments you've passed to
it and returns a result of type int. If those assumptions are violated,
all bets are off.
To avoid that kind of problem, *always* add a #include for the
header(s) that declares any function(s) you're calling, so the
compiler can tell you if you got the arguments wrong.
> Thanks also for the style and other issues - Now the code runs, I will
> focus on those as well.
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Most of the following is OT on comp.lang.c. You have been warned:
Cool. I think I know why it messed up - assuming your code is
being compiled on an x86 machine and the C calling conventions
haven't changed in the years since I checked.
Firstly, time.h declares the time() function. Your compiler will
run with out it; in the absense of a declaration, the compiler
assumes that the function has an arbritrary number of parameters
and that it returns int. This much is true of all C implementations.
time() is in the standard library, so chances are when the linker
sees a reference to time it will do the right thing, even though
the compiler has the surrounding code all kerfuddled.
Now, on an x86 machine, the way this is implemented by the compiler
is that in your main function, all the parameters are popped onto
the stack. In the call to time(), there are none.
Then time() runs, and for each parameter it expects, it pops it
off of the stack. time() expects a single parameter, so it pops
that off - but it isn't there! So instead it pops something else
off the stack (some of i or j or str). Lucky you again, whatever
it gets, it doesn't try to use as a pointer, because that would
probably segfault your program. Chances are your OS zeroed out
your stackspace for security reasons so it reads a NULL pointer.
So now the stack is in a different place from where you started.
It then returns a time_t value, which the compiler understands
to be an int. Lucky for you, all int values are returned in the
EAX register (or RAX on a 64-bit system). So rand() does in fact
receive a proper time_t value - assuming my assumptions.
Now, this time_t value is pushed onto the stack, as an int.
rand() expects an unsigned int, and these will be the same
size in all likelihood, so all is well for rand().
Now, we're a back into main(). And remember, the stack is offset
because of your bogus call to time(), but since it's still some-
where valid for your program, the OS doesn't know or care enough
to terminate it.
Now, i and j and str point to the wrong place because your
compiler understands them as relative to the stack pointer -
which is in the wrong place. Luckily you allocated an obscene
amount of space for str. What I think it happening is that the
"\n" you give to printf() is going to be put right before str.
So you're still safe from OS termination, even though you're
bull-in-a-china-shop-ing your own stack space.
Now we get into the fun stuff: you load up str and print it.
All is well, since although str is in the wrong place, it's
at least consistently wrong so your code can use it.
Then we get to printf(). The compiler sets the "\n" in place,
running over str (who had no right to be where he was) with
a newline and \0.
You then do str[10] = '\0', which is sweet of you but
useless because str[1] == '\0' thanks to the above \n
conunduggery. So from this point all, no matter how
you print str[], you'll be printing that "\n".
All that, plus whatever alignment tricks your compiler does,
which are Who Knows What.
That's my theory anyway. The official C answer is that using
time() as you did is Undefined Behavior, which would be within
the spec to format your hard drive, crash your space shuttle
or set fire to your home, depending on your OS and perhiphials.
Andrew
time() needs a parameter. Or an argument. I'm not sure. RTFM.
Isn't that against the reasoning behind ASCII? Just wondering..
> > int main()
> > {
> > char str[81];
>
> Where does 81 come from?
Oh dear lord.
> > puts(str);
> > for ( j = 0; j < 10; ++j ) {
> > printf("%c", str[j] );
> > }
> > printf("%s\n", str);
>
> You forgot to NULL-terminate it this time. str[10] will still
> be 0 from the last call, but it's dangerous and unclear to rely
> on such things.
He's only printing it. Not changing it. But then again, this seemingly
innocuous code may be well over my code comprehension capabilities.
The function takes a parameter.
The call needs an argument.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within
Indeed. Discussions also need arguments; you can see the source of my
confusion. ;-)
> > int main()
> > {
> > char str[81];
>
> Where does 81 come from?
<sigh> Not so's you'd notice.
Worth putting effort into, nonetheless. Trolls get tired, grow up, or
die, eventually.
> Then time() runs, and for each parameter it expects, it pops it
> off of the stack. time() expects a single parameter, so it pops
> that off - but it isn't there! So instead it pops something else
> off the stack (some of i or j or str). Lucky you again, whatever
> it gets, it doesn't try to use as a pointer, because that would
> probably segfault your program. Chances are your OS zeroed out
> your stackspace for security reasons so it reads a NULL pointer.
>
> So now the stack is in a different place from where you started.
Except ... the callee doesn't actually pop arguments off the stack. It
reads the arguments from an address relative to either the stack
pointer or the frame pointer (and leaves them there).
If it modified the stack pointer, the RET instruction would load something
other than the return address into EIP.
Windows API functions do remove their arguments from the stack, as they
use the "stdcall" (aka "pascal") calling convention (except for variadic
functions). But the ANSI C functions in MSVCRT all use "cdecl", which
leaves it to the caller to remove the arguments, and the caller will
remove whatever it put there, regardless of whether it was correct for
the callee.
Because the stdcall convention is sensitive to the size of the argument
list, any functions which use that convention are "decorated" with the
size of the argument list. E.g. if time() used stdcall, the symbol
exported from the DLL would be called _time@4 on 32-bit systems or _time@8
on a 64-bit system. But the OP's code would refer to just _time (functions
with no prototype use the cdecl convention), so a link error would occur.
But it must move the stack pointer? Otherwise recursion would
be very difficult.
> If it modified the stack pointer, the RET instruction would load something
> other than the return address into EIP.
>
Hmm. Since the program didn't crash I assumed it was doing
something different with EIP, but perhaps not. Probably not,
actually.
> Windows API functions do remove their arguments from the stack, as they
> use the "stdcall" (aka "pascal") calling convention (except for variadic
> functions). But the ANSI C functions in MSVCRT all use "cdecl", which
> leaves it to the caller to remove the arguments, and the caller will
> remove whatever it put there, regardless of whether it was correct for
> the callee.
>
> Because the stdcall convention is sensitive to the size of the argument
> list, any functions which use that convention are "decorated" with the
> size of the argument list. E.g. if time() used stdcall, the symbol
> exported from the DLL would be called _time@4 on 32-bit systems or _time@8
> on a 64-bit system. But the OP's code would refer to just _time (functions
> with no prototype use the cdecl convention), so a link error would occur.
>
Cool. I did not know that.
I have yet to experience an ABI where passing the wrong number of arguments
to a function can result in the stack getting adjusted to the wrong value.
So far as I can tell, every ABI I've used has had the trait that the
adjustments both ways are performed in the same place.
I've seen a lot of OTHER things go wrong if the wrong number of arguments
are provided, but I've yet to see that go wrong.
-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet...@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
What about the stdcall ABI, when you don't do fancy linking based on
the parameter list? The callee will end up popping either too few or
too many arguments from the stack.
In K&R C, before prototypes were introduced, cleaning up the stack
(more precisely, deallocating space allocated for arguments) pretty
much had to be the responsibility of the caller. There was no
special form of declaration for variadic functions like printf,
which meant that a call could legitimately pass an arbitrary
number of arguments to any arbitrary function. Since the callee
had no way of knowing how many arguments had actually been passed,
it couldn't perform the necessary cleanup.
Many current C implementations are descended from older
implementations, and maintain the same calling conventions,
partly to cater to old code and partly just out of inertia.
The requirement that variadic functions may not be called without
a visible prototype caters to implementations that allow either
the caller or the callee to clean things up, but implementations
don't necessarily take advantage of that.
I have apparently never used it, or if I have, I never happen to have seen
something with the wrong number of arguments in it.
> On Feb 4, 2:54�pm, Richard Heathfield <r...@see.sig.invalid> wrote:
> > Michael Foukarakis wrote:
> > > On Feb 4, 12:08 pm, Richard Heathfield <r...@see.sig.invalid>
> > > wrote:
> > >> Michael Foukarakis wrote:
> > > Indeed. Discussions also need arguments;
> >
> > <sigh> Not so's you'd notice.
>
> Worth putting effort into, nonetheless. Trolls get tired, grow up, or
> die, eventually.
They get tired much faster if you ignore them.
Brian
--
Day 367 of the "no grouchy usenet posts" project
>> I doubt you want exactly this. You probably want to use
>>
>> rand() % (sizeof src - 1)
> Oh my goodness! I did mean that, and I have been bitten
> by this bug in my own code. (Though in that case, it was
> a one-off password generator and as I recall I just kept
> running it until I got a string without any \0 characters
> truncating the string.)
I mention in passing that gcc (4.1 here), even with no
optimisation, turns strlen(src) into a constant. I'd feel
a bit odd relying on that, but it's nice to know that at
least on the only compiler I regularly use (modulo a whole
host of different versions), can be relied on to turn the
apparently inefficient into the optimal.
Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1
Out of curiousity, what disassembler do you use to tell that?
This actually bit us once. There's another rule:
strcpy(dest, "string literal");
is magically transformed into
memcpy(dest, "string literal", 15);
But. In one of the branches of the Linux kernel tree, someone thought it
would be a great idea to provide a special hand-tuned assembly implementation
of memcpy, which saved a single instruction by returning 0 instead of the
destination pointer.
Enter a lump of code roughly to the effect of:
strcat(strcpy(dest, "foo"), "bar");
and a kernel panic as strcat tried to copy into a null pointer.
After some consideration, we determined that this did not constitute a
toolchain bug.
(The question isn't as trivial as it might seem, because freestanding
environments are in some cases permitted to have a really weird standard
library. There is an option to disable that transformation, but it seemed
smarter to just fix the memcpy() implementation.)
Sun cc will do the same, very handy. I guess anywhere the programmer
could use sizeof in place of strlen, the compiler does the same.
--
Ian Collins
>> I mention in passing that gcc (4.1 here), even with no
>> optimisation, turns strlen(src) into a constant. I'd feel
>> a bit odd relying on that, but it's nice to know that at
>> least on the only compiler I regularly use (modulo a whole
>> host of different versions), can be relied on to turn the
>> apparently inefficient into the optimal.
>>
>
> Out of curiousity, what disassembler do you use to tell that?
Probably no disassembler, just "gcc -S":
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Overall-Options.html#index-S-75
It works here too (4.3.2):
----v----
#include <string.h>
int main(void)
{
return strlen("The quick brown fox jumps over the lazy dog");
}
----^----
$ gcc -S strlen.c
----v----
main:
.LFB2:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
movl $43, %eax
leave
ret
----^----
Cheers,
lacos
I didn't.
Phil
(more in headers, but please think before looking)
> I mention in passing that gcc (4.1 here), even with no
> optimisation, turns strlen(src) into a constant.
Are you quite sure it's gcc?
glibc's <string.h> includes <bits/string.h>, which has a whole host of
macros and inline asm. The actual strcpy() macro is:
#define strcpy(dest, src) \
(__extension__ (__builtin_constant_p (src) \
? (sizeof ((src)[0]) == 1 && strlen (src) + 1 <= 8 \
? __strcpy_a_small ((dest), (src), strlen (src) + 1) \
: (char *) memcpy ((char *) (dest), \
(__const char *) (src), \
strlen (src) + 1)) \
: __strcpy_g ((dest), (src))))
Try the test again with "#undef strcpy".
>> Except ... the callee doesn't actually pop arguments off the stack. It
>> reads the arguments from an address relative to either the stack
>> pointer or the frame pointer (and leaves them there).
>>
>
> But it must move the stack pointer? Otherwise recursion would
> be very difficult.
For the cdecl calling convention, the caller adjusts ESP prior to the
call (either explicitly or by PUSHing the arguments), then restores it
upon return. The two will always cancel each other out, regardless of
whether the arguments are correct for the function being called.
And miss all the fun? :'(
No. I just hammered randomly on the keys and ran a random program
instead of the compiler. Looking at my command-line history, it
appears I ran 'rm' instead, so I can't even tell you what code
it actually was 'compiling'.
> glibc's <string.h> includes <bits/string.h>, which has a whole host of
> macros and inline asm. The actual strcpy() macro is:
>
> #define strcpy(dest, src) \
> (__extension__ (__builtin_constant_p (src) \
> ? (sizeof ((src)[0]) == 1 && strlen (src) + 1 <= 8 \
> ? __strcpy_a_small ((dest), (src), strlen (src) + 1) \
> : (char *) memcpy ((char *) (dest), \
> (__const char *) (src), \
> strlen (src) + 1)) \
> : __strcpy_g ((dest), (src))))
>
> Try the test again with "#undef strcpy".
Nice hatstand, Roger.
It wasn't a daft question.
>> glibc's <string.h> includes <bits/string.h>, which has a whole host of
>> macros and inline asm. The actual strcpy() macro is:
>>
>> #define strcpy(dest, src) \
>> (__extension__ (__builtin_constant_p (src) \
>> ? (sizeof ((src)[0]) == 1 && strlen (src) + 1 <= 8 \
>> ? __strcpy_a_small ((dest), (src), strlen (src) + 1) \
>> : (char *) memcpy ((char *) (dest), \
>> (__const char *) (src), \
>> strlen (src) + 1)) \
>> : __strcpy_g ((dest), (src))))
>>
>> Try the test again with "#undef strcpy".
>
> Nice hatstand, Roger.
It shows that it could well have been glibc rather than gcc which was
responsible for the transformation.
--
Flash Gordon
Opinions may vary.
>>> glibc's <string.h> includes <bits/string.h>, which has a whole host of
>>> macros and inline asm. The actual strcpy() macro is:
>>>
>>> #define strcpy(dest, src) \
>>> (__extension__ (__builtin_constant_p (src) \
>>> ? (sizeof ((src)[0]) == 1 && strlen (src) + 1 <= 8 \
>>> ? __strcpy_a_small ((dest), (src), strlen (src) + 1) \
>>> : (char *) memcpy ((char *) (dest), \
>>> (__const char *) (src), \
>>> strlen (src) + 1)) \
>>> : __strcpy_g ((dest), (src))))
>>>
>>> Try the test again with "#undef strcpy".
>>
>> Nice hatstand, Roger.
>
> It shows that it could well have been glibc rather than gcc which was
> responsible for the transformation.
The only thing which could transform strlen() to strcpy() would be gbugc.
> On Feb 4, 10:13�pm, "Default User" <defaultuse...@yahoo.com> wrote:
> > Michael Foukarakis wrote:
> > > On Feb 4, 2:54�pm, Richard Heathfield <r...@see.sig.invalid>
> > > wrote:
> > > > Michael Foukarakis wrote:
> > > > > On Feb 4, 12:08 pm, Richard Heathfield <r...@see.sig.invalid>
> > > > > wrote:
> > > > >> Michael Foukarakis wrote:
> > > > > Indeed. Discussions also need arguments;
> >
> > > > <sigh> Not so's you'd notice.
> >
> > > Worth putting effort into, nonetheless. Trolls get tired, grow
> > > up, or die, eventually.
> >
> > They get tired much faster if you ignore them.
>
> And miss all the fun? :'(
I don't know about anyone else, but I don't find the destruction of the
newsgroup to be fun.
Brian
--
Day 368 of the "no grouchy usenet posts" project
Oops; this was supposed to be a response to Seebs' reply about turning
strcpy() into memcpy().
But a similar point applies here: glibc's <bits/string.h> has:
#define strlen(str) \
(__extension__ (__builtin_constant_p (str) \
? __builtin_strlen (str) \
: __strlen_g (str)))
So I would expect "#undef strlen" to change this.
You might, but apparently some of this stuff is also hardwired in the compiler
in some cases. It may vary with architecture, though.
extern int strcpy(char *, char *);
int main(void) {
return 0;
}
gcc says:
t.c:1: warning: conflicting types for built-in function `strcpy'
So how about:
extern unsigned int strlen(const char *);
int main(void) {
return strlen("foo");
}
gcc produces:
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $3, %eax
leave
ret
So, yes, it's gcc, not the headers.
craaaaazy stuff, huh.
Yes, *please*, do us all a favor and miss the fun.
Kiki still labors under two misconceptions:
1) That the words I type have magical properties, like Medusa's
head, such that mere exposure to them will cause horrific
results in the viewer. I know this sounds crazy on the surface,
but it is the only explanation I can find for why it is not
enough for him to simply not read these words (*), but rather he
must work extra hard to prevent others from reading them as well.
2) That he is the Supreme Executive Commander In Charge here, and
that nothing is allowed to escape his view and comment. Note,
in passing, that this fact (that Kiki will not allow any
item/thread in CLC to exist without at least one piece of input
from him) was used quite effectively by HfC, to prove that Kiki
was lying about his killfile usage. (**)
(*) Well, to be more accurate (and we know how highly accuracy is
prized in this newsgroup), to read and ignore them - but the effect
is the same. I.e., the effect is the same as if he never read them.
(**) This was one of many thoroughly effective such proofs. Do not
labor under the misconception that this was the only one.
> So how about:
>
> extern unsigned int strlen(const char *);
> int main(void) {
> return strlen("foo");
> }
Right; confirmed with gcc 4.3.4 on Linux/x86.
-fno-builtin disables this, as does -ffreestanding (older
versions of gcc have the former but not the latter).
I don't think I've ever seen an implementation where the
callee/caller responsible for cleaning up a stack is
different for fixed verses variadic functions. That's
not to say there aren't any!
But note that promotion is _not_ to be applied to arguments
to named parameters of narrow type. Also, there are risc
systems where 'variable' arguments are passed on the stack,
instead of via the default, registers.
--
Peter