0

While creating strjoin I noticed a strange phenomenon. When outputting a value strs in function strjoin()

These results were printed

123

Why?

#include <stdio.h>
#include <stdlib.h>

char    *strjoin(int size, char **strs, char *sep)
{
    char *new;

    if (!(new = malloc(sizeof(char) * size)))
        return (NULL);

    printf("%s", strs[1]);
    return (NULL);
}

#include <unistd.h>

int     main(void)
{
    char* b[4] = {"123", "456", "789", "245"};
    char *p;
    int i = 0;
    int size = 5;
    char a[4] = {',', 'a', 'b', '\0'};

    p = *b;

    strjoin(5, &p, a);
}
ikegami
  • 322,729
  • 15
  • 228
  • 466
hochan
  • 159
  • 7
  • `main()` should return integer as defined int. – EsmaeelE Feb 04 '20 at 19:52
  • 3
    `sizeof (char)` always equals to one then redundant. – EsmaeelE Feb 04 '20 at 19:53
  • 1
    Express exactly what do you want? – EsmaeelE Feb 04 '20 at 19:55
  • 2
    Your array has 4 elements, so I'm not sure why are you requesting 5 of them. "123" is shown twice because `p` is located after `b` on stack (hence, has lower address). You're passing address of `p`, but it is only 1 element, so indexes greater than 0 actually reference values from `b`, e.g. `strs[1]` is `b[0]`. – Alex Skalozub Feb 04 '20 at 19:56
  • 1
    This code not compile. provide [mcve] version of program. – EsmaeelE Feb 04 '20 at 19:58
  • 1
    Presumably you want to call `ft_strjoin(4, b, a);`, note using `b` instead of `*p`. – Stephan Schlecht Feb 04 '20 at 20:03
  • 2
    @EsmaeelE, Since C99(?), the `return 0` can be omitted from `main`. – ikegami Feb 04 '20 at 20:06
  • @ikegami explicit better than implecit. Never relay on specific version or compiler. https://stackoverflow.com/a/18721336/7508077 – EsmaeelE Feb 04 '20 at 20:43
  • 2
    @EsmaeelE, Poppycock. You can target C99 if you want to. (And it's over 20 years old now!) Furthermore, the linked post isn't relevant. I didn't say to change the declaration, only that the `return EXIT_SUCCESS;` is optional according to the C language, *even when declared as `int main(...)`*. (In fact, `main` must be declared to return `int` in C99.) Note that I didn't mention any compiler or version thereof. – ikegami Feb 04 '20 at 20:58
  • 1
    @EsmaeelE, Did you actually read the answers to the question you linked? They say the same thing I did. Top answer: "*Whether `return 0;` should be omitted or not is open to debate.*" [The implication is that you *may* omit it.] Second answer: "*You may omit the return statement from `main()`.*" – ikegami Feb 04 '20 at 21:03
  • The OP has written a function called `strjoin()` (which, BTW, does not join a pair of strings!) Strongly suggest learning about `strcat()` – user3629249 Feb 04 '20 at 22:40
  • why allocate memory through the call to `malloc() and then 1) not use that allocated memory and 2) fail to pass that allocated memory to `free()` before exiting? – user3629249 Feb 04 '20 at 22:43
  • regarding: `char a[4]` 1) let the compiler count the number of elements. 2) since it is not used in the sub function, the third parameter to `strjoin()` can be eliminated AND the array `a[]` can be eliminated – user3629249 Feb 04 '20 at 22:46
  • the function: `strjoin()` returns a NULL pointer regardless of the success/fail of the call to `malloc()` AND the call to `strjoin()` in `main()` does not check the returned value. Suggest removing those `return NULL;` statements, change the returned type to `void` for the function `strjoin()` – user3629249 Feb 04 '20 at 22:48
  • @ikegami OK and thanks. You are correct. I check it as C99 its correct and `main()` without return statement will implicitly return 0; and not bad is happen from c99 to later standards. But for completeness I'll check c89 this not happen and `main()` return non zero, for me 37. For c99 and earlier standards gcc -S put `movl $0, %eax` in `main()` and I think this is what return for main. because changing it in .s file to `movl $5, %eax` change return value to 5. I use `echo $?` to see return value. But For c89, `gcc -S -std=c89` not add this command. – EsmaeelE Feb 05 '20 at 16:08
  • @hochan, The program your posted does not output what you claim is posted. Why did you change your answer to something incorrect again? I'm reverting the addition of the misinformation – ikegami Feb 05 '20 at 16:56

1 Answers1

9

In order for it to be valid to use the value referenced by str[1], str must point to an array of at least two char* elements. In your demonstration, it points to p, which is a single char*. Your program therefore invokes Undefined Behaviour, and thus your program is invalid.

It's unclear what you are trying to accomplish. Perhaps you wanted

char **p = &( b[0] );
strjoin(4, p, a)

Keep in mind that an array used where a pointer is expected degenerates into a pointer to its first elements, so the above is equivalent to the following:

char **p = b;
strjoin(4, p, a)

or simply

strjoin(4, b, a)

(The first parameter to strjoin isn't being used in your demonstration, but I imagine it's expected to be the number of elements in *str, so I have adjusted it the argument accordingly.)

ikegami
  • 322,729
  • 15
  • 228
  • 466
  • Thank you very much I understand! – hochan Feb 05 '20 at 01:35
  • Excellent answer. Clarification No need to use extra double pointer to pointer `char **p`. – EsmaeelE Feb 05 '20 at 16:23
  • @EsmaeelE, Are you saying there's no reason to use `p`? The answer already demonstrates that. – ikegami Feb 05 '20 at 16:48
  • "...an array used where a pointer is expected...." -- It might be helpful to be more explicit about this. Arrays decay to pointers to their first elements in _most_ expressions, the exceptions being when the array is an operand to the unary `&` address operator, or when the array is an operand to the `sizeof` operator, or when the array is a string literal used to initialize an array. – ad absurdum Feb 05 '20 at 17:20