Newbie pointers and reversing question

K

Kelly B

Flash said:
Kelly B wrote, On 15/04/07 17:49:
One obvious mistake is that strlen returns a size_t but %d expects an
int. Since size_t is required to be an unsigned integer type this
guarantees you are doing it wrong. If you are using C99 (and it is
unlikely your implementation fully supports C99) you can use
printf("%zu",strlen(b_str));
Otherwise
printf("%lu",(unsigned long)strlen(b_str));
which will work for incredibly long strings.

It is very important to use the correct format specifiers for printf if
you want to get correct results.

If that does not work post you exact code, the complete program that
shows the problem, using copy & paste rather than retyping. Normally I
would say trim it down to a minimal example, but in this case you are
starting from a minimal program anyway.

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

void reverse(char* begin, char* end)
{
char tmp;
while(begin < end)
{
tmp = *begin;
*begin = *end;
*end = tmp;
++begin;
--end;
}
}

int main(int argc, char* argv[])
{
char a_str[8] = "abc def";
char *b_str = "abc def" ;

printf("str: %s\n",a_str);
reverse(a_str,a_str + strlen(a_str) - 1);
printf("str: %s\n",a_str);

while(*b_str!='\0')
{
printf("%c",*b_str);
b_str++;
}

printf("\n%lu",(unsigned long)strlen(b_str));
return 0;
}

The printf at the end(the one printing strlen(b_str))prints 0 when the
while loop is used
while(*b_str!='\0'){
printf("%c",*b_str);
b_str++;
}

If i remove the while loop it prints the correct value 7!How does the
while loop affect the value of printf?Seems strange to me!
 
K

Kelly B

If i remove the while loop it prints the correct value 7!How does the
while loop affect the value of printf?Seems strange to me!

Oh silly me .
i have already modified the pointer b_str an then trying to printf the
length of the string!.Sorry to bother everyone!
 
F

Flash Gordon

Kelly B wrote, On 15/04/07 18:28:
Oh silly me .
i have already modified the pointer b_str an then trying to printf the
length of the string!.Sorry to bother everyone!

No you know why it is important to post complete compilable examples. :)
 
C

CBFalconer

Kelly said:
Oh!yes it should have returned 7(i made a silly counting mistake
there) but when i included the line printf("%d",strlen(b_str));
it prints 0 and it is confusing me.

What type does strlen return? You lied to the compiler.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
M

Michael Jarrod

Hi all,

Thanx for your comments, they have been very informative!

I've concluded from this that the memory that is created
to store the contents of b_str is read-only.

I'm currenlty using gcc 4.0 with the -std=c99 switch, some
have said that the program should have worked with a c99
compiler. I'm not sure to the degree of compliancy of GCC
regarding this particular issue.



-Mich
 
F

Flash Gordon

Michael Jarrod wrote, On 15/04/07 22:18:
Hi all,

Thanx for your comments, they have been very informative!

I've concluded from this that the memory that is created
to store the contents of b_str is read-only.

Then you have not understood correctly. b_str is not read-only, it is a
pointer that you are allowed to modify. However, it is initialised to
point to a string literal that you are not allowed to attempt to modify.
This is all covered in the comp.lang.c FAQ at http://c-faq.com/ which I
pointed you at. Giving you the benefit of the doubt that you failed to
see that post, go and read question 1.32 (it is also Q8.5) and all of
section 6.
I'm currenlty using gcc 4.0 with the -std=c99 switch, some
have said that the program should have worked with a c99
compiler.

Then you have mis-understood what was said. Your program modifying a
string literal is not required to work EVER with ANY compiler. However,
it required C99 (or extension to C89) to even compile.
> I'm not sure to the degree of compliancy of GCC
regarding this particular issue.

If the program printed out "You are an idiot and your mother is a cross
between a wombat and a goblin" it still would not affect compliance. If
you modify a string literal literally ANYTHING is allowed to happen as
far as all versions of the C standard are concerned.

The gcc documentation points you at its C99 status page that will tell
you where it fails to comply to C99. To get as close as it comes to
compliance you also need the -pedantic switch, and you would be well
advised to use -Wall -Wextra -O as well.
 
I

Ian Collins

Flash said:
The gcc documentation points you at its C99 status page that will tell
you where it fails to comply to C99. To get as close as it comes to
compliance you also need the -pedantic switch, and you would be well
advised to use -Wall -Wextra -O as well.

Why -O?
 
F

Flash Gordon

Ian Collins wrote, On 15/04/07 22:54:

Because without any optimisation it does not do sufficient analysis to
warn of variable possibly being read before they are written. It's in
the documentation.
 
I

Ian Collins

Flash said:
Ian Collins wrote, On 15/04/07 22:54:



Because without any optimisation it does not do sufficient analysis to
warn of variable possibly being read before they are written. It's in
the documentation.

OK, thanks. I hadn't spotted that (man gcc on my box spews forth a 178
page document!).
 
C

CBFalconer

J

Jack Klein

Michael said:
I have the following code piece of code:

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

void reverse(char* begin, char* end) {
char tmp;
while(begin < end) {
tmp = *begin;
*begin = *end;
*end = tmp;
++begin;
--end;
}
}

int main(int argc, char* argv[]) {
char a_str[8] = "abc def";
a_str[7] = '\0';

printf("str: %s\n",a_str);
reverse(a_str,a_str + strlen(a_str) - 1);
printf("str: %s\n",a_str);

char* b_str = "abc def";

printf("str: %s\n",b_str);
reverse(b_str,b_str + strlen(b_str) - 1);
printf("str: %s\n",b_str);
return 0;
}

when I use a_str for the parameter to the function reverse
everthing is ok, however when b_str is used the program
crashes when the line containing *begin = *end is executed.

I've always thought that the definitions of a_str and b_str
were more or less equivelent. Can someone explain where I
have gone wrong.

The char* b_str declaration will not work unless you have a c99
compiler. If it does work it will declare an initialized string
somewhere in memory that is not modifiable.

Chapter and verse, please, where the C standard states that string
literals are stored in "memory that is not modifiable". Or even
mentions the possibility of such a type of memory.

The memory may or may not be modifiable. The C standard says nothing
about it. The type of a string literal is "array of char", and
specifically NOT "array of const char". This is almost certainly
because of the indisputable fact that string literals existed in the
language long before the 'const' type qualifier and corresponding
keyword did.

Attempting to modify a string literal in C produces undefined behavior
not because the type is const, but because the C standard specifically
states that it produces undefined behavior.

On some implementations, the string literal would actually be
modified, that being one possible consequence of undefined behavior.

On some implementations, the writes would generate no errors in
themselves, but the string literal would be unchanged, that being
another possible consequence of undefined behavior.

And on still other implementations, the program will "crash" when it
attempts to modify the string literal, that being yet another possible
consequence of undefined behavior.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
S

Scott Fluhrer

Jens Thoms Toerring said:
Michael Jarrod said:
I have the following code piece of code:
#include <stdio.h>
#include <string.h>
void reverse(char* begin, char* end)
{
char tmp;
while(begin < end)
{
tmp = *begin;
*begin = *end;
*end = tmp;
++begin;
--end;
}
}
int main(int argc, char* argv[])
{
char a_str[8] = "abc def";

Here you obtain memory for 8 characters.
a_str[7] = '\0';

This isn't necessary, the '\0' is already at the end of
"abc def" even though you don't see it;-) A string en-
closed in double quotes always contains the trailing '\0'.

Obnit: not quite always. If the OP had written:

char a_str[7] = "abc def";

there there would be no trailing \0. Of course, your statement is correct
in the context the OP gave.
And here you obtain a pointer for a char pointer that
points to what's a "string literal", e string that the
compiler created for you somewhere in memory and that
is read-only (even though some implementations actually
let you get away with modifying it you better always
assume it's read-only - that's what it's supposed accor-
ding to the C standard).

Or to be more precise, any attempt to write into it will cause undefined
behavior (that is, the C standard places no requirement on what the
implementation might do at this point). It might 'work', it might cause a
page fault, it might work (but other string literals in the program may be
modified as well), it might be ignored, or it might do anything else the
implementation feels like.
 
P

pete

Scott said:
Or to be more precise,
any attempt to write into it will cause undefined
behavior (that is, the C standard places no requirement on what the
implementation might do at this point).
It might 'work', it might cause a
page fault, it might work
(but other string literals in the program may be
modified as well),

I think that's one of the more relevant cases as concerns
the decision to not define modification of string literal objects.

If

*"Hello" = '\0';

succedes, then what does a subsequent

puts("Hello");

do?

The answer is:
Nobody cares.
If you're going to write code like that,
then you're on your own.
 
K

Keith Thompson

Flash Gordon said:
Ian Collins wrote, On 15/04/07 22:54:

Because without any optimisation it does not do sufficient analysis to
warn of variable possibly being read before they are written. It's in
the documentation.

But that doesn't affect C99 compliance. Reading an uninitialized
variable (in most cases) invokes undefined behavior in either C90 or
C99; the compiler is not required to diagnose the error. Using "-O",
or better yet "-O3", will likely give you more and better diagnostics,
but I don't know of any that are relevant to conformance. (Though, of
course, I could be missing something.)

More generally, invoking an optimization option is likely to give you
additional warnings on any compiler.
 
F

Flash Gordon

Keith Thompson wrote, On 16/04/07 21:36:
But that doesn't affect C99 compliance.

I did not intend to say it did, although re-reading I can see it could
be read that way.
> Reading an uninitialized
variable (in most cases) invokes undefined behavior in either C90 or
C99; the compiler is not required to diagnose the error. Using "-O",
or better yet "-O3", will likely give you more and better diagnostics,
but I don't know of any that are relevant to conformance. (Though, of
course, I could be missing something.)

The documentation only says you need -O.
More generally, invoking an optimization option is likely to give you
additional warnings on any compiler.

I'm not convinced how general it is. The compiler could do the analysis
even if it does not rearrange (optimise) the code. However, I'm no
expert on compilers and the is straying rather off topic.
 
N

Nick Keighley

It is required to work when begin and end point to elements of the
same array (6.5.8.5). Otherwise the behaviour is undefined.
Anyway, I think it is better to pass such a function a pointer to
the first character and the length of the string to be reversed.

why? Two pointers don't seem an unreasonable interface.
 
A

Army1987

Flash Gordon said:
Ian Collins wrote, On 15/04/07 22:54:

Because without any optimisation it does not do sufficient analysis to
warn of variable possibly being read before they are written. It's in the
documentation.


Maybe even -O3...
 
A

Army1987

Nick Keighley said:
why? Two pointers don't seem an unreasonable interface.
I can't see how it is better than using (char *str, size_t length).
And it invokes UB if begin and end point to totally unrelated addresses of
memory.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,619
Members
45,314
Latest member
HugoKeogh

Latest Threads

Top