Pointer arithmetic question.

A

Adrian Sch

Hello! I am doing some exercises from K&R 2nd edition and I seem to be stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}

And here's a version that doesn't work:
char *strcpy(char * s, char * t)
{

while(*s++)
;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}
It seems that for some reason the while(*s++) is 0 so it doesn't increment. Why? What am I missing here?
 
T

tom st denis

Hello! I am doing some exercises from K&R 2nd edition and I seem to be stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;}

int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}

And here's a version that doesn't work:
char *strcpy(char * s, char * t)
{

while(*s++)
;

Ask your self, where does "s" point now. (hint: compare the value of
's' in this version against the other via printf("%p\n", s)).
while((*s++=*t++))
;

return ;}

int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}

It seems that for some reason the while(*s++) is 0 so it doesn't increment. Why? What am I missing here?

Once you figure out where 's' points to after the while(*s++) loop
you'll figure out the bug in the 2nd copy.

Tom
 
G

Greg Martin

Hello! I am doing some exercises from K&R 2nd edition and I seem to be stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}

And here's a version that doesn't work:
char *strcpy(char * s, char * t)
{

while(*s++)
;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}
It seems that for some reason the while(*s++) is 0 so it doesn't increment. Why? What am I missing here?

I made a couple of changes to your program. Some to make my compiler
happy, some for readability and one to make the program work. The
pre-increment will return the value after incrementing where as the
post-increment returns it then increments the value. In your version you
begin the to write after the NIL, in mine I overwrite it.

#include <stdio.h>

char* strcpy(char* s, char* t) {
while(*++s);

while((*s++=*t++) != '\0');

return s;
}

int main(void) {
char message[100]="string1";
char* message2="string2";

strcpy(message, message2);
printf("%s\n", message);

return 0;
}
 
B

BartC

Adrian Sch said:
Hello! I am doing some exercises from K&R 2nd edition and I seem to be
stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;
}

Do you mean strcat rather than strcpy?
 
B

Ben Bacarisse

Adrian Sch said:
Hello! I am doing some exercises from K&R 2nd edition and I seem to be
stuck: Here's a working copy of a custom strcpy:

No, it's a not-quite working version on strcat.
char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

What is x for? You never use it.
while((*s++=*t++))
;

return ;

You compiler should have complained to you about this. Adjust the
warning level to the highest you can. There's no reason not to get the
maximum help you can.
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}

Also, get into the habit of layingout your code using some standard or
other. I know that the above layout could have been due to Google's
awful Usenet interface, but some of it is yours. Pick a style and stick
to it.
And here's a version that doesn't work:
char *strcpy(char * s, char * t)
{

while(*s++)
;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}
It seems that for some reason the while(*s++) is 0

That makes not sense. A while loop always ends when it's condition is
zero. That's as true of the working as of the the non-working version.
so it doesn't increment. Why? What am I missing here?

Play computer: draw a string and a pointer to it, then step through what
this loop does until you see what's wrong. I'll gladly tell you, but
you'll learn more by stepping through it yourself:

+------------+
s: | o |
+-----+------+
|
V
+-----+-----+-----+-----+-----+-----+-----+-----+
| s | t | r | i | n | g | 1 | \0 |
+-----+-----+-----+-----+-----+-----+-----+-----+

(you'll need a fixed-width font to see this.)
 
J

James Kuyper

Hello! I am doing some exercises from K&R 2nd edition and I seem to be stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}

And here's a version that doesn't work:
char *strcpy(char * s, char * t)
{

while(*s++)
;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}
It seems that for some reason the while(*s++) is 0 so it doesn't increment. Why? What am I missing here?

The 'x' is irrelevant. You may find it easier to understand what's going
on if you remove it. Your working version had the equivalent of:

while(*s) s++;

The version that didn't work had the equivalent of:

while(*s++);

When s points at "string1", how many times does s++ get executed with
the working version of the code? How many times with the version that
failed? In each case, where does s point after the loop is finished
executing?
 
E

Eric Sosman

Hello! I am doing some exercises from K&R 2nd edition and I seem to be stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;
}

That's not a strcpy() work-alike. Looks more like strcat(),
which is a different breed of, well, cat.
And here's a version that doesn't work:
char *strcpy(char * s, char * t)
{

while(*s++)
;

while((*s++=*t++))
;

return ;
}

This isn't a work-alike for any of the standard string
functions, and certainly not for strcpy() or strcat(). A name
like strabut() might describe what it does, which is: "Copy the
`t' string to the memory area just after the `s' string, leaving
the '\0' at the end of `s' undisturbed."

I think what you've overlooked is that the test in the first
`while' loop will detect the '\0' character *and* will advance
`s' past that character. If you want to append the `t' characters
to `s', you should deposit the first of them right where the '\0'
was originally; as things stand, you're depositing that first
character just after the '\0'.
 
E

Eric Sosman

[...]
I made a couple of changes to your program. Some to make my compiler
happy, some for readability and one to make the program work. The
pre-increment will return the value after incrementing where as the
post-increment returns it then increments the value. In your version you
begin the to write after the NIL, in mine I overwrite it.

#include <stdio.h>

char* strcpy(char* s, char* t) {
while(*++s);

This fails if `s' points to an empty string: It skips right
over the '\0' at the beginning and starts exploring the trackless
wilderness after the terminator. (It's very bad to find yourself
on the wrong side of The Terminator -- just ask Ahhnold.)
 
G

Greg Martin

[...]
I made a couple of changes to your program. Some to make my compiler
happy, some for readability and one to make the program work. The
pre-increment will return the value after incrementing where as the
post-increment returns it then increments the value. In your version you
begin the to write after the NIL, in mine I overwrite it.

#include <stdio.h>

char* strcpy(char* s, char* t) {
while(*++s);

This fails if `s' points to an empty string: It skips right
over the '\0' at the beginning and starts exploring the trackless
wilderness after the terminator. (It's very bad to find yourself
on the wrong side of The Terminator -- just ask Ahhnold.)

Very true. Thanks Eric. There's a reason I hate those little shortcuts!
 
A

Adrian Sch

marți, 30 octombrie 2012, 20:00:49 UTC+2, Greg Martin a scris:
Hello! I am doing some exercises from K&R 2nd edition and I seem to be stuck: Here's a working copy of a custom strcpy:
char *strcpy(char * s, char * t)

char x;
while(x=*s)
while((*s++=*t++))

return ;

int main(void)

char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;



And here's a version that doesn't work:
char *strcpy(char * s, char * t)
while(*s++)
while((*s++=*t++))

return ;

int main(void)

char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;


It seems that for some reason the while(*s++) is 0 so it doesn't increment. Why? What am I missing here?



I made a couple of changes to your program. Some to make my compiler

happy, some for readability and one to make the program work. The

pre-increment will return the value after incrementing where as the

post-increment returns it then increments the value. In your version you

begin the to write after the NIL, in mine I overwrite it.



#include <stdio.h>



char* strcpy(char* s, char* t) {

while(*++s);



while((*s++=*t++) != '\0');



return s;

}



int main(void) {

char message[100]="string1";

char* message2="string2";



strcpy(message, message2);

printf("%s\n", message);



return 0;

}

First, thanks to all of you for the replies.

Second, you are right, this a not-working strcat version.

Third, this is a very subtle problem and quite hard to identify consideringmy limited knowledge. Because my real question was why the "while(*s++);" gets skiped in the code. Because I was using a debuger and I was expecting some additional action. But because there was no block of code to execute and go back again to the while test, the while test was executed at once (very fast). Am I right or wrong? Because that seemed stupid to me, how the while get skipped while *s was pointing to s.
Now for the real question, that I didn't ask. I figured that the subtlety of the postfix increment is causing my trouble. Because once the *s is pointing at null, it is incremented one more time and the future copies of *t value go after the null. So when I am printing message, I have concatenated the string, but unfortunately after the null, and that makes it just (not random) garbage as far as printf is concerned.
I used a quick hack to fix it: using the prefix operator. That worked! But I think that this is wrong because if the first string's first character was null,then I'd repeat the whole affair from before and have concatenated the string after the null.

Forth, here's the fix(as sugested by some of you):
char *strcpy(char * s, char * t)
{

while(*s)
s++;

while((*s++=*t++))
;

return ;
}

Fifth, Is there any other way to keep simple and elegant, but on just one line of code? Or maybe a messier way, but also to fit in the while testing block? I am thinking and if else shortcut notation, but I don't master the idiom that well to do this apparently.
 
K

Keith Thompson

Adrian Sch said:
Hello! I am doing some exercises from K&R 2nd edition and I seem to be
stuck: Here's a working copy of a custom strcpy:

char *strcpy(char * s, char * t)
{

char x;
while(x=*s)
s++;

while((*s++=*t++))
;

return ;
}
int main(void)
{
char message[100]="string1";
char * message2="string2";
strcpy(message, message2);
printf("%s", message);
return 0;

}
[...]

As several other people have pointed out, that's an implementation of
strcat, not of strcpy.

Here's a reformatted version:

char *strcpy(char *s, char *t)
{
char x;
while(x = *s)
s++;

while((*s++ = *t++))
;
return;
}

int main(void)
{
char message[100] = "string1";
char *message2 = "string2";
strcpy(message, message2);
puts(message);
return 0;
}

I've fixed the indentation and added consistent whitespace in
some places. I've also changed your printf() call to puts(),
so that it prints a newline after the message.

Some remarks, in addition to what others have said:

You need to add "#include <stdio.h>" if you're going to call either
printf or puts.

The names "strcpy" and "strcat" are reserved, as are all identifiers
starting with "str" (or "mem", or "wcs") and a lowercase letter.
Which means that, unless you're actually implementing the C standard
library, you shouldn't call your own function "strcpy" or "strcat".
You could call it "str_cat", for example, or "my_strcat".
 
E

Eric Sosman

[...]
Forth, here's the fix(as sugested by some of you):
char *strcpy(char * s, char * t)
{

while(*s)
s++;

while((*s++=*t++))
;

return ;

Looks like you didn't read Ben Bacarisse's response.
}

Fifth, Is there any other way to keep simple and elegant, but on just one line of code? Or maybe a messier way, but also to fit in the while testing block? I am thinking and if else shortcut notation, but I don't master the idiom that well to do this apparently.

Yes! The one line you need is

#include <string.h>

That is, in real programs you should use the library's functions
instead of writing your own replacements. But this isn't a "real
program;" it's a learning exercise. So, as a learning challenge:
Can you get the whole thing on one line?

If your screen is wide enough, the answer, again, is Yes!

char*mystrcpy(char*s,char*t){while(*s)s++;while(*s++=*t++);return/*wrong!*/;}

Okay, okay, so how about "one loop" instead of "one line?"

Once again, Yes!

char *mystrcpy(char *s, char *t) {
for (s += strlen(s); *s++ = *t++; );
return /*wrong*/ ;
}

But if you don't want to use existing library functions then I
think the answer is No. You need to do two distinct things: Find
the end of the `s' string, and copy the `t' characters to it. It's
*possible* to combine those two operations into one loop, but I can
think of no way that could be called "elegant" or "simple."
 
A

Adrian Sch

[...]
Forth, here's the fix(as sugested by some of you):
char *strcpy(char * s, char * t)
{
while(*s)
s++;
while((*s++=*t++))
;
return ;
Looks like you didn't read Ben Bacarisse's response.
I did read it. If you are referring to code formatting then know that I am formatting my code, but it just how it looks when I paste it here.
 
A

Adrian Sch

Can you get the whole thing on one line?



If your screen is wide enough, the answer, again, is Yes!



char*mystrcpy(char*s,char*t){while(*s)s++;while(*s++=*t++);return/*wrong!*/;}
This is kind of obvious, and is not what I was having in mind, but thanks for the tip anyway:D


Okay, okay, so how about "one loop" instead of "one line?"



Once again, Yes!



char *mystrcpy(char *s, char *t) {

for (s += strlen(s); *s++ = *t++; );

return /*wrong*/ ;

}
This is interesting!
But if you don't want to use existing library functions then I

think the answer is No. You need to do two distinct things: Find

the end of the `s' string, and copy the `t' characters to it. It's

*possible* to combine those two operations into one loop, but I can

think of no way that could be called "elegant" or "simple."



--

Eric Sosman

(e-mail address removed)

So there's no way to translate
while(*s)
s++;

into something like (pseudocode)
while(*s?s++:break)
the code above doesn't compile. Why is not possible to cram a if statement into a while testing block? Stupid question probably, but that's my way of learning.
 
B

Ben Bacarisse

Adrian Sch said:
[...]
Forth, here's the fix(as sugested by some of you):
char *strcpy(char * s, char * t)
{
while(*s)
s++;
while((*s++=*t++))
;
return ;
Looks like you didn't read Ben Bacarisse's response.
I did read it. If you are referring to code formatting then know that
I am formatting my code, but it just how it looks when I paste it
here.

Eric is referring to the missing expression in the return statement and,
possibly, my associated comments about getting your compiler to tell you
as much as you can get it to. You shouldn't pass up the chance to get a
helping hand from the compiler. By default, I compile with as many
warnings turned on as I can.

Some warnings you will then ignore, but you'll learn from finding out
why you can ignore a particular warning in a particular situation.
 
B

Ben Bacarisse

Adrian Sch said:
So there's no way to translate
while(*s)
s++;

(I've fixed the indentation -- it's so important in fragments like this)
into something like (pseudocode)
while(*s?s++:break)

Yes. Borrowing your conditional expression, you can write

while (*s ? s++ : 0);

but

while (*s && s++);

is simpler. However, the original is simpler still so there is nothing
at all to be gained.

You could also stick with while (*s++); and compensate for being one
place ahead of yourself later, but that works out (in that case) to be
even worse.
the code above doesn't compile. Why is not possible to cram a if
statement into a while testing block? Stupid question probably, but
that's my way of learning.

It's fun to try these things out but they are often worse than you
imagine. For one thing, simpler can often be harder to read, and most
code is read far more often that it's written (and frequently by people
who have no idea what on earth you were thinking when you wrote it).

But, as I said, it can be fun. I just wasted a few minutes writing both
loops as one, but I didn't post it because the results were, as
expected, awful. I came up with:

while (*s || *t)
if (*s) s++;
else *s++ = *t++, *s = 0;

and

while (*s || *t)
if (!*s++) s[-1] = *t++, *s = 0;

and even (with it all in the condition of the loop):

char *r = 0;
while (*s++ || !r && (r = s - 1) || (*r++ = *t++));

(In my defence, I never though it would be worth the attempt -- the
desire to tinker simply got the better of me.)
 
J

James Kuyper

....
So there's no way to translate
while(*s)
s++;

When you talked about "just one line of code", Eric apparently assumed
(as did I) that you were referring to the entire function. It's not
possible to make that code any simpler or more elegant, as you
requested, but it is trivial to turn it into a one-liner:

while(*s) s++;
into something like (pseudocode)
while(*s?s++:break)
the code above doesn't compile. Why is not possible to cram a if statement into a while testing block? Stupid question probably, but that's my way of learning.

The problem with that piece of code is that while statements can contain
expressions, expressions can never contain statements.
The third operand of the ?: operator is required to be a conditional
expression. The "break" keyword isn't any kind of an expression, it's
only permitted use is as part of a break statement. Break statements are
only allowed inside the body of a while() loop or a switch statement.
You're trying to use it in the controlling condition, which is required
to be an expression; it's not part of the loop body.

The expression 0 would be perfectly acceptable in this context, and
would have the same effect you're trying to achieve by using "break":

while(*s?s++:0);

You could also use

while(*s && s++);

but both of those are unnecessarily "clever", and I don't mean that as a
compliment. If I made a mistake in writing them down (which is quite
possible), that would demonstrate why such "cleverness" is a bad idea. I
don't think that either of those statements is any kind of improvement over

while(*s) s++;
 
G

Greg Martin

while (*s || *t)
if (*s) s++;
else *s++ = *t++, *s = 0;

and

while (*s || *t)
if (!*s++) s[-1] = *t++, *s = 0;

and even (with it all in the condition of the loop):

char *r = 0;
while (*s++ || !r && (r = s - 1) || (*r++ = *t++));

(In my defence, I never though it would be worth the attempt -- the
desire to tinker simply got the better of me.)

That kind of thinking can lead to no good. :)
http://www.ioccc.org/2012/blakely/blakely.c
 
E

Eric Sosman

[...]
Forth, here's the fix(as sugested by some of you):
char *strcpy(char * s, char * t)
{
while(*s)
s++;
while((*s++=*t++))
;
return ;
Looks like you didn't read Ben Bacarisse's response.
I did read it. If you are referring to code formatting then know that I am formatting my code, but it just how it looks when I paste it here.

Perhaps you should pay attention to other things Ben wrote,
referring to places I highlighted with /*wrong*/ comments...

(Kudos to Ben, by the way: On first reading, I completely
missed the problem he pointed out.)
 
S

S R

[snip]
     char *r = 0;
     while (*s++ || !r && (r = s - 1) || (*r++ = *t++));
^^^^^
I think there is a problem with the above. Once we reach the end of
string s, s is not guaranteed to point to a location containing 0 as
its value, assuming s as being sent in by the caller of the function
(in your earlier examples you made ",*s =0" which was the correct).
The concatenation happens through r but the check *s++ is problematic,
isn't it?

Cheers,
 

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,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top