Journal Articles

CVu Journal Vol 12, #1 - Jan 2000 + Letters to the Editor
Browse in : All > Journals > CVu > 121 (30)
All > Journal Columns > LettersEditor (132)
Any of these categories - All of these categories

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: The Wall

Author: Administrator

Date: 03 January 2000 13:15:34 +00:00 or Mon, 03 January 2000 13:15:34 +00:00

Summary: 

Body: 

And Again

Dear Francis,

There is of course more than one way to skin a cat and I thought you might be interested in the way I would write a function to remove dashes. In this function I have preferred pointers over indexes:

char *remove_dashes(char *string) {
  char *src = string;
  char *dst = string;
  while ((*dst = *src++) != '\0')
    if (*dst != '-')
      ++dst;
  return string;
}

Although I know the test against the nul character in the while expression is not necessary I like to use it as I think it makes it clearer that I really did mean the assignment. In general I think the simpler the expression the better as there is less to read and less to misinterpret. Obviously one doesn't want to go too far and make things cryptic! All C/C++ programmers know that zero means false and any non-zero value means true, and I don't think that using this fact is likely to confuse anyone. But, as I say, in this case if I had used

  while (*dst = *src++)

someone might misread it as

  while (*dst == *src++)

hence the explicit comparison against the nul character.

Slight digression: another thing in this while expression that might be worth mentioning is that it relies on the fact that the result of an assignment is the rightmost term; in this case the character value stored at *src, before src is post-incremented. You can write

  a = b = c;

which, as assignment is right-associative, is equivalent to

  a = (b = c);

and in both cases the value of the rightmost term, c, will be assigned to a and b. (This is why operator=() member functions should return a value.)

Out of interest, do you know what will happen in these two statements?

  a = b = c, d = e;
  a = (b = c, d = e);

In the first c is assigned to a and b, e is assigned to d. In the second c is assigned to b, e is assigned to d and also to a.

By the way, I didn't understand your version of removedashes() at all. It didn't look to me as though it would work. Have I misunderstood something fundamental or is this a case of a programmer "improving" code and introducing a bug? (I understand you had other things on your mind while preparing the last issue of C Vu.) I read somewhere, I don't remember where, that programmers are likely to introduce more bugs in small functions than in larger functions, up to a certain size, and then the bug count rises again. Maybe it's related to the fact that apparently more car accidents occur within a few streets of home. Perhaps we switch to automatic, and make mistakes. (I don't know if the statistics take account of the fact that presumably we spend more time driving a few streets from home than we do anywhere else.)

One thing about my own solution occurs to me, that it may spend a lot of time needlessly assigning characters to themselves, until it comes across the first dash. If this function was frequently used for long strings one might want to investigate improving its performance, against the cost of increasing the complexity of the code, and the possibility of making the function very quick to get the wrong answer.

You asked for an implementation of the following prototype:

char[] eliminate(char these[], char from[]);

I'm afraid my compiler, MS VC++ 6, didn't like that char[] return type. Here is my effort:

char *eliminate(char these[], char from[]) {
  char *src = from;
  char *dst = from;
  while (*src){
    if (strchr(these, *src) != 0) ++src; // skip unwanted char
    else *dst++ = *src++;
  }
  *dst = '\0'; // null-terminate result
  return from;
}

alternatively, if I'm not permitted to call strchr()...

char *eliminate(char these[], char from[]){
  char *src = from;
  char *dst = from;
  while ((*dst = *src++) != '\0') {
    for (char *p = these; *p; ++p) if (*dst == *p) break;
    if (*p == '\0')++dst; // don't overwrite wanted char
  }
  return from;
}

Thank you for a very interesting journal.

Anthony Hay.

My coding for removedashes() illustrates a variation on the miss-typing of '==' as '=', this time I put '==' where I intended '='. There is a difference between C and C++ when it comes to the assignment operators. In C they return a value, in C++ they return a reference to the lhs (first operand). Note that this is conventionally a non-const reference for udts (it is required to be for fundamental types). Note that the explicit comparison with '\0' does nothing to help catch that typo.

Note that the error message on the return value emphasises that arrays and pointers really are not interchangeable despite so many programmers thinking they are.

I think that some programmers may not like your use of break. And quite a few would advocate that the prototype of your function be:

  char *eliminate(char const these[], char from[]; 

Anyone offer an implementation that does not use break nor call another function?

Notes: 

More fields may be available via dynamicdata ..