0

I'm trying to direct the strncat function. I understand most of it and can write this a diff way, but I can't figure out how to write a longer version of while (!(*dest++ = *src++)).

char *_strncat(char *dest, char *src, int n)
{
    char *ret = dest;
    while (*dest) /* same as: while (dest[0] !- '\0') */
    {
        dest++; /* w. each loop, array is shifted left until it's empty */
    }
    while (n != 0)
    {
         if (!(*dest++ = *src++)) /* <=========here */
            return ret;
        n--;
    }
    *dest = 0;
    return (ret);
}

Can someone show and explain how to expand that line so I can direct it and learn how it works? Thanks!

dbconfession
  • 1,147
  • 2
  • 23
  • 36

2 Answers2

3

The line:

if (!(*dest++ = *src++))
    return;

can be expanded to:

char temp1 = *src++; // copy from *src to temp1 and increment src
char temp2 = (*dest++ = temp1); // Copy temp1 to *dest, increment dest, and also copy value to temp2
if (!temp2) return ret; // return if the value that was copied is a null byte

The use of post-increment is important here. It ensures that we copy from *src to *dest before the pointers are incremented. So to expand it further, it would be:

char temp1 = *src;
src = src + 1;
char temp2 = (*dest = temp1);
dest = dest + 1;
if (!temp2)
    return ret;
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I think postincrement part should be expanded too as it makes the most confusion as I suspect. – Eugene Sh. Feb 23 '17 at 22:57
  • @Barmar thanks! I'm working through this. When i hit `char temp2 = (dest = temp1);` it returns `error: assignment makes pointer from integer without a cast [-Werror=int-conversion] char temp2 = (dest = temp1);` – dbconfession Feb 23 '17 at 23:27
  • @dbconfession change that line to: `char temp2 = (*dest = temp1);` – Aaron Feb 23 '17 at 23:28
  • @Barmar Your first expansion output correctly but is failing one unit check. Your second expansion worked AFTER fixing with Aaron's suggestion. If you either fix first or remove it and make aaron's fix in the second expansion I will mark it as answered. – dbconfession Feb 23 '17 at 23:48
  • I'd appreciate it if you came back with the information about the unit test tomorrow. I'm not sure what the problem is with my first code. – Barmar Feb 23 '17 at 23:51
  • The only thing I see with your first example is a missing ; otherwise it should work. – Aaron Feb 24 '17 at 19:17
  • Thanks @AaronTaggart that's probably what it was. – Barmar Feb 24 '17 at 21:24
1

Basically it is copying the values of src into dest, incrementing, and then checking for null (or the null terminator). So you could expand it this way:

*dest = *src; // Copy the value
if (*dest == '\0') // Was it null?
    return; // We are done!
dest++; // go to next character
src++; // go to next character

One point of confusion might be coming from the use of an = rather than a ==. The = operator always returns the value that was assigned, this allows for daisy chains of assignment:

int a, b, c;
a = b = 0; // sets both a and b to 0
if (c = a) // sets c = a, then performs if(0) which is false.

Note: Technically the src and dest pointers are incremented even in the case of the return, so this would properly expand to the below, but that is just noise as to understanding what the code is doing:

*dest = *src; // Copy the value
if (*dest == '\0') // Was it null?
{
    dest++; // not really needed but happens
    src++; // not really needed but happens
    return; // We are done!
}
dest++; // go to next character
src++; // go to next character
Aaron
  • 1,893
  • 16
  • 24
  • 1
    Except that `dest++` and `src++` still happen even if `return` happens. – Dietrich Epp Feb 23 '17 at 23:02
  • So you are correct that src and dest get incremented in that case, but it is a moot point as far as the algorithm is concerned (or understanding how the algorithm works). But I am impressed with that find! I updated the answer. – Aaron Feb 23 '17 at 23:12