Extremeely basic programming question.

Is this something to do with the distinction between putting the ++ after the variable versus before it? Because personally, I deal with that distinction by avoiding it entirely. If I want to increment a variable, then I use a statement that increments the variable and does nothing else. If a compiler wants to optimize that into something else, that’s the compiler’s problem, not mine.

Not really. It’s a comparison operation that occurs after the copy is done. But you are wise to avoid pre- and post-increments. They are artifacts of the DEC instruction set and can cause confusion. Efficiency is rarely an issue anymore, clarity always is.

Much as I dislike having ++ and = return values, it seems straightforward why this code works… the while loop will only terminate after the condition evaluates to false, and the value of the condition is the value of the last byte copied. So the while loop will only terminate after the 0-byte has been copied.

Why is this such a violation of structured programming? Because the condition is “impure” (evaluating it causes a side effect; to wit, a byte to be copied and src and dest to increment)? The moment the while loop was written with an empty body, it should’ve been obvious the condition was intended to be impure.

(Perhaps instead of “impure”, I should say “effectful”; truly “pure” conditions (in the sense of being not only side-effect free but also evaluating to the same value every time) are completely useless in loops, either causing the loop body to never run or to run forever)

I don’t see what’s so confusing about it, C’s syntax allow for assignments to be done in conditionals, and the leftmost assignment will be used as the value in the conditional (that is, if you assign 0 it acts as false, else true). ETA: Indistinguishable put it better, “=” returns a value equal to the expression on the right hand side.

Aside from that quirk of C, the only other confusing thing is that the post-increment operator binds higher than the dereference operator, so ++ increments the pointer instead of the character. I guess the only other thing to note is that the post-increment operator doesn’t affect the quirk I mentioned in the first paragraph (that is int i = 0; while (i++) { } is a while loop that will never execute any code), because post-increment tells it to evaluate after the while loop does.

All you’re really doing is a very annoying to read version of



char x = 1;
while ( x ){
  *dest = *src;
   x = *dest;
  ++dest;
  ++src;
}


(which itself has problems, but that’s the most literal working interpretation I came up with).

Unfortunately there’s a ton of problems with it:

  1. You have to copy the pointer of both src and dest because there’s no way to recover the starting address (but then that’s why I never increment pointers unless I’m freeing the data – a preference most programmers don’t share).

  2. Without parens, it’s hard to tell what operator executes when, that is, is it (*src)++ or *(src++)? It’s not hard to figure out, but the construction takes some looking at to figure out.

  3. It uses the trick I mentioned in the first paragraph, which is so uncommonly used, and bypasses the concept of using boolean values. No, I don’t mean the bool type, I mean the fact that you’re using a value in a conditional and implicitly assuming 0 is FALSE and !0 is TRUE. This is guaranteed in the C spec, I think, but using a value in a conditional just feels really, really wrong. I guess the annoying bit is that it uses a side-effect rather than a primary effect to get the job done.

(A bug of the form

if (x = 0){}

Is a really fun one to find for newbie programmers, because most of them already forget that = and == aren’t the same. Then the language goes and says “you want to use an assignment of the value 0=FALSE instead of checking for a zero value? OKAY!”).

The problem with the C copy loop is it’s a very poor way to code something that should have been done with the strcpy() function.

Well, what if you have no standard library functions, then what*? :stuck_out_tongue:

  • There are some compilers that target old video game consoles. They lack library functions to the degree that you have to write the print functions yourself with asm blocks.

Then you add a comment explaining what you’re doing.

This. My Father worked for a railroad. In the early 1970’s they wanted to computerize the scheduling and control of trains. This was formerly done manually by dispatchers. They tried twice to hire computer experts to come up with programs that could do this task, and both were complete failures. Finally they took their 3 best dispatchers and sent them off for six months to learn to program computers, and they were finally able to get something working.

Those dispatchers knew how to do their jobs through experience. They couldn’t explain to anyone else how to do it, and in many cases didn’t consciously even know how they did it. There was no possible way for them to explain to a programmer that didn’t know anything about train dispatching what was needed.

If you really understand the problem you are trying to solve, then you can probably get something working even if you are a terrible programmer. A good programmer will also have something that is easy to understand, debug and maintain. But if you don’t understand the problem you are trying to solve, then you may never get this wonderful program to work right.

And as another nitpick, couldn’t the empty braces be replaced by a single semicolon?

Yes. But then it wouldn’t be structured :smiley:

The reason I teach my C/C++ students *while (*dest++ = src++); is they may encounter it in old code written by someone else. It’s certainly easier to understand it in an introductory class than to spend a day or two trying to figure it out by yourself. My hope that they’d finally be able to say “oh! that’s strcpy()!”.

Er, why? Surely structured programming was never about such syntactic minutiae as whether “;” was an acceptable abbreviation for an empty code block.

You noticed the smiley face right? Er, I should have used the sarcasm thing.

Anyway, some people consider code structure just to be syntactical form, with no regard to the actual process. So I was mocking that attitude.

Then y’oughtta try to find some of our earlier threads like this. I try to find some and post links a little later on this afternoon, but I gotta run right now . . .

I swear C++ programmers have destroyed the utility of every distinction so that it can apply to C++ as a programming language. OO? We’ve got that! Strong typing? We’ve got that! Not like those scripting languages… And to be sure they get it both ways they then permit overloading and implicit conversions… ugh.

The fact is, most languages have strong typing in the sense that every value has a well-defined type. Variables may have types, but they don’t have to. For instance, lisps in general are strongly typed—that is, for one interpretation, there is a predicate which can test a value; and, every value has a predicate. (A different interpretation might be: no expression will be evaluated if it doesn’t type-check, though C cannot guarantee this interpretation.) Here’s an example from an interactive session in Racket:


> (define a 10)
> (integer? a)
#t
> (set! a "a string")
> (integer? a)
#f
> (string? a)
#t
> 

For languages without predicates (e.g., C), you would have to rely on declared types. In this sense, C collapses the variable/value distinction—at least as far as types are concerned. Unfortunately C also collapses other things making it rather unsafe. (Though it is not hard to see that this is a feature of C; less so of C++.)

For other languages, a value might be able to be interpreted in multiple ways. Wikipedia gives the example of PHP interpreting “1000” and “1e3” as equal numbers but unequal strings (ugh) and if this isn’t weak typing I don’t know what would be. I don’t know much about Perl, perhaps it does this sort of nonsense, too.

Ah, alright.

YES and NO !!!
It DOES matter that the ++ are after the variables instead of before. If you put them before, they’d get incremented before the byte got copied, and the byte copied in each iteration would get copied from/to the wrong place!

And your (ETA: and Chronos) solution (always put increments on a statement by themselves) is, IMHO, the absolute best clear-cut unambiguous foolproof correct way to do it! (But what do I know? I’m an old FORTRAN programmer, where you didn’t have ++ operators.)

Clarity? What clarity? We don’t need no steenkin’ clarity! That snippet I showed from K&R is, like I said, one of the worst examples I’ve seen, especially coming from The Original Source Of All C !

I’ve only glanced at the other subsequent posts so far. At first glance, I do suspect that I’m right: Most of you don’t know what that awfully-written code really does. But give me a chance to read your posts more carefully first. Later this afternoon. I gotta run now . . .

You missed the point (if you read K&R): That IS the strcpy() function!

Okay, quick answer before I gotta run . . .

I’m not sure if any of the above posts really fully got this, although on quick glance I see that some were at least leaning in the right direction. I’ll read them all more thoroughly later this afternoon.

That one-line string copy is an abomination of structured programming because it does exactly what structured program is NOT supposed to do – or, from another point of view, it does exactly what that kind of while ( ) loop is specifically designed NOT to do.

That kind of while ( ) loop is SPECIFICALLY specified to create a “top-controlled” loop – That is, the very FIRST thing it does in each iteration is to test the condition, and then skip out if false. How, then, does it copy up to and including the zero byte, rather than stopping at the zero byte before copying it?

Because the copy operation (as well as both the incrementing operations) are done in the processing of evaluating the conditional, BEFORE actually testing the result of that conditional. In other words, this code semi-surreptitiously puts some actual do-something code BEFORE the conditional test. In other words, in the guise of being a top-controlled loop, it is not a top-controlled loop at all! In fact, it puts ALL its do-something code before the test, effectively making it a bottom-controlled loop (which has the test at the end of each iteration instead of the beginning).

It took me a good 45 minutes of studying that one line of code, the first time I saw it, to figure that out! And that, IMHO, is a total mis-use and abuse of the very purpose and intention of the while ( ) loop!