Newbie pointers and reversing question

M

Michael Jarrod

hi,

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.



-Mich
 
J

Jens Thoms Toerring

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'.
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";

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).

And please note that defining new variables somewhere
in the body of a function is only allowed if you have
a C99 compliant compiler (or a compiler that supports
this as an extension). You may run into trouble with
this with some older compilers or if you force your
compiler to only accept C89 code.
printf("str: %s\n",b_str);
reverse(b_str,b_str + strlen(b_str) - 1);

Since reverse() modifies the string you pass to it you
here try to modify the string literal the pointer 'b_str'
is pointing to, but since the string literal is read-only
your program crashes.
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.

As you see they aren't, only 'a_str' is a string that you
may modify, while 'b_str' is just a pointer initialized to
point to a read-only string literal. If you would instead
made 'b_str' point to the first element of 'a_str' then
everything would work fine.

Regards, Jens
 
A

Army1987

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

void reverse(char* begin, char* end)
Wouldn't it be clearer if you passed (char *begin, int length)?
{
char tmp;
while(begin < end)
{
tmp = *begin;
*begin = *end;
*end = tmp;
++begin;
--end;
}
}
int main(int argc, char* argv[])
You never use arguments, so couldn't you just use int main(void) ?
{
char a_str[8] = "abc def";
a_str[7] = '\0';
If you write:
char a_str[] = "abc def";
the "correct" length for the string (including the terminal 0 -- in this
case, 8) is used.
BTW the second istruction is always useless, as a string literal always
contains the terminating 0. But see http://c-faq.com/ansi/nonstrings.html
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.

They aren't.
http://c-faq.com/decl/strlitinit.html
 
F

Flash Gordon

Michael Jarrod wrote, On 15/04/07 14:38:
hi,

I have the following code piece of code:

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

You are not using anything from string.h, including it does no harm but
if you are using nothing from it then there is no benefit either.
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';

This is pointless, as the array is large enough it will be null
terminated anyway. In fact, since you only want an array large enough
and don't need extra space you could do
char a_str[] = "abc def";
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.

You were lucky. Although what you did is wrong (it invokes undefined
behaviour) it could have "worked" or done anything else.
I've always thought that the definitions of a_str and b_str
were more or less equivelent.

No, they are vastly different.
> Can someone explain where I
have gone wrong.

Amongst other things you have not checked the FAQ for the group which is
available at http://c-faq.com/ something you should always do. Your
question is in there twice as 1.32 and also 8.5, I would suggest you
read section 6 as well.
 
C

CBFalconer

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.

(I modified your code to reduce vertical space)

--
<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
 
K

Kelly B

Michael Jarrod wrote:
...snip...
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;
}

I have a question here. Why does strlen(b_str) return the value 0 ,it
should have been 8 isn't it?
 
A

Army1987

Flash Gordon said:
Michael Jarrod wrote, On 15/04/07 14:38:

You are not using anything from string.h, including it does no harm but if
you are using nothing from it then there is no benefit either.
Really? Read this line again:

And this:
See nothing?
 
F

Flash Gordon

Kelly B wrote, On 15/04/07 16:06:
Michael Jarrod wrote:


I have a question here. Why does strlen(b_str) return the value 0 ,it
should have been 8 isn't it?

No, it should not return 8, it should return 7. I very much doubt it
returns 0, what makes you think it does?

PS, I missed the call to strlen when replying to the OP, string.h should
therefore be included as the OP did.
 
F

Flash Gordon

Army1987 wrote, On 15/04/07 16:29:
Really? Read this line again:


And this:

See nothing?

I see that I need new contact lenses as my current ones obviously do not
work.
 
G

Guest

Michael said:
hi,

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';

There's no need for this. a_str[7] will already be set to '\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.

This is in the FAQ: please take a look at <http://c-faq.com/decl/
strlitinit.html>.
 
C

conrad

hi,

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.

-Mich

One is an array; the other is a pointer to an array.
The latter can also be thought of as a special kind
of array. One that has the constraint of being unmodifiable.
When this constraint is violated, you invoke undefined
behavior.

There is possibly another issue, with how
you rely on the pointer value of begin to be
'less than' the pointer value of end. I don't
think it is meaningful to relate pointer values
this way. Though I could be wrong. I just don't
have access to a standard at this moment.
 
L

Lew Pitcher

hi,

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.

Not really. a_str and b_str can be used similarly, but their
definitions are different.
Can someone explain where I have gone wrong.

You define a_str as
char a_str[8] = "abc def";
which makes a_str an "array of 8 char", initialized such that
a_str[0] == 'a',
a_str[1] == 'b',
a_str[2] == 'c',
a_str[3] == ' ',
a_str[4] == 'd',
a_str[5] == 'e',
a_str[6] == 'f', and
a_str[7] == '\0'

Because of this definition, the contents of a_str (each array element)
are permitted to be altered programmatically, but the origin of the
a_str array (that is to say, &a_str[0]) is not. IOW, it is perfectly
legal (and has no undefined behaviour) to
a_str[6] = 'q';
or even
a_str[0] = a_str[6];
but it is not legal to
a_str = &a_str[3];

On the other hand, you define b_str as
char* b_str = "abc def";
which makes b_str a "pointer to char", initialized such that it points
to a spot in memory where
*b_str+0 = 'a',
*b_str+1 = 'b',
*b_str+2 = 'c',
*b_str+3 = ' ',
*b_str+4 = 'd',
*b_str+5 = 'e',
*b_str+6 = 'f',
*b_str+7 = '\0',

Because of this definition, the contents of b_str (each array element)
are /not/ permitted to be altered programmatically, but the origin of
the b_str array (that is to say, b_str ) is. IOW, it is perfectly
legal (and has no undefined behaviour) to
b_str = &b_str[2];
but if you
b_str[2] = 'x';
then you get into trouble.
 
A

Army1987

There is possibly another issue, with how
you rely on the pointer value of begin to be
'less than' the pointer value of end. I don't
think it is meaningful to relate pointer values
this way. Though I could be wrong. I just don't
have access to a standard at this moment.

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.
 
F

Flash Gordon

conrad wrote, On 15/04/07 17:08:
hi,

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.

-Mich

One is an array;
Yes.

> the other is a pointer to an array.

No, it is a pointer to a char not a pointer to an array. That the
character it points to is the first character of an unnamed array does
not affect what b_str itself is. After all, you could later make b_str
point to a char variable.
The latter can also be thought of as a special kind
of array.

That is a very bad way to think of a pointer. It is true for the string
literal "abc def" but NOT true for the pointer.
> One that has the constraint of being unmodifiable.

The string literal that b_str points to is not modifiable, but both
a_str and b_str are modifiable.
When this constraint is violated, you invoke undefined
behavior.

Modifying the string literal invokes undefined behaviour, which is
probably what you meant.
There is possibly another issue, with how
you rely on the pointer value of begin to be
'less than' the pointer value of end. I don't
think it is meaningful to relate pointer values
this way. Though I could be wrong. I just don't
have access to a standard at this moment.

As the are pointers to the same object (either a_str or the sting
literal) it is perfectly legal and required to give the result most
people would expect. It is only if they do not point to the same object
(or 1 past the end) that you have a problem.
 
K

Kelly B

Flash said:
Kelly B wrote, On 15/04/07 16:06:

No, it should not return 8, it should return 7. I very much doubt it
returns 0, what makes you think it does?

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.
 
P

pete

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.

Try

printf("%u\n", (unsigned)strlen(b_str));

to avoid undefined behavior from trying to output
a size_t type value, as an int type value.
 
K

Kelly B

....snip..
Oh!yes it should have returned 7
Try

printf("%u\n", (unsigned)strlen(b_str));

to avoid undefined behavior from trying to output
a size_t type value, as an int type value.


It still prints 0 when i use :
printf("%lu",(unsigned long)strlen(b_str));

ive tried this on both Visual Studio and gcc 3.4.4.I really don't seem
to understand the reason!
 
F

Flash Gordon

Kelly B wrote, On 15/04/07 17:49:

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.

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.
 
F

Flash Gordon

Kelly B wrote, On 15/04/07 18:12:

It still prints 0 when i use :
printf("%lu",(unsigned long)strlen(b_str));

ive tried this on both Visual Studio and gcc 3.4.4.I really don't seem
to understand the reason!

Then you have some other problem. Looking in my crystal ball I see that
the 42nd byte in your source file is incorrect. In other words, how can
we see what is wrong if we cannot see what you have done?

Try posting a complete compilable program showing the problem.
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top