0

I'm new to pointers and I can already see how confusing they can be. I have tried to look this up in several threads and google but they don't quite return what I'm looking for maybe out of my inexperience.

I'm being passed an array of strings and I have to pass it again to another function however I'm extremely confused on how to do this and don't know what * or & to use or where.

My code:

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

char    *ft_strcat(char *dest, char *src)
{
    unsigned int    c;
    unsigned int    count;

    count = 0;
    while (dest[count] != 0)
    {
        count++;
    }
    c = 0;
    while (src[c] != '\0')
    {
        dest[c + count] = src[c];
        c++;
    }
    dest[c + count] = 0;
    return (dest);
}

int size_str(char *str)
{
    int c;

    c = 0;
    while (str[c] != '\0')
    {
        c++;
    }
    return (c - 1);
}

int size_all(int size, char *strs[], char *sep)
{
    int i;
    int counter;

    i = 0;
    counter = 0;
    counter += size_str(sep) * (size - 1);
    while (i < size)
    {
        counter += size_str(strs[i]);
        i++;
    }
    return (counter);
}

char    *ft_strjoin(int size, char **strs, char *sep)
{
    int     i;
    char    *str;

    str = malloc(sizeof(char) * size_all(size, strs, sep));
    str = strs[0];
    i = 1;
    while (i < size)
    {
        str = ft_strcat(str, strs[i]);
    }
    return (str);
}

int main(void)
{
    char    *sep = "   ";
    char    a1[] = "Batata";
    char    a2[] = "frita";
    char    a3[] = "\'e";
    char    a4[] = "melhor";
    char    a5[] = "que";
    char    a6[] = "Banana";
    char    *strs[] = {a1, a2, a3, a4, a5, a6};
    char    *final = ft_strjoin(6, strs, sep);

    printf("%s", final);
}

I thought that size all would have to have an extra dereference operator on the declaration of the function and an reference operator when I call it, but this works just fine. Am I doing something wrong or am I just misunderstanding how pointers work? Don't I have to add an extra * each time I pass it?

Finally why doesn't while (src[c] != '\0') work?

MiguelP
  • 416
  • 2
  • 12
  • `str = malloc(sizeof(char) * size_all(size, strs, sep)); str = strs[0];` That doesn't make sense. The second statement overwrites the `malloc` result which means that memory is lost. – kaylum Jul 21 '21 at 23:11
  • @kaylum you just fixed my incompetence, thanks tons! – MiguelP Jul 21 '21 at 23:18
  • Are you prohibited from using built-in functions like `strlen()`? – Barmar Jul 22 '21 at 00:19
  • `str = strs[0]` should be `strcpy(str, strs[0])` – Barmar Jul 22 '21 at 00:20
  • `size_str()` shouldn't subtract 1. You're not counting the null byte in the loop, so you don't have to subtract it. – Barmar Jul 22 '21 at 00:23
  • Either `size_all()` or `ft_strjoin()` needs to add 1 for the final null terminator at the end of the joined string. – Barmar Jul 22 '21 at 00:25
  • The one problem I *don't* see is with passing parameters between the functions. You got that all right. – Barmar Jul 22 '21 at 00:26

2 Answers2

1

I have worked lately about this problematic, string joint. I noticed that you forgot to add an if condition where the size would be 0. Moreover, the while loop need an iteration, which means that it will give you an infinite loop.

You can find as follows some adjustment to your code:

int     i;
char    *str;
int     j;
int     k;

i = 0;
k = 0;
str = (char *)malloc(sizeof(char) * sizeall(size, strs, sep) + 1));
if (size == 0)
    return (0);
while (i < size)
{
    j = 0;
    while (strs[i][j])
        str[k++] = strs[i][j++];
    j = 0;
    if (i < size - 1)
        while (sep[j])
            str[k++] = sep[j++];
    i++;
}
str[k] = '\0';
return (str);

Feel free to ask me if there is something you did not understand, and good luck.

Hodormad
  • 21
  • 1
  • 5
1

In size_str:

There's nothing wrong with while (src[c] != '\0'), but return (c - 1); is causing an off-by-one error with your string lengths. The NUL byte wasn't counted in the loop, there's no need to subtract 1.

In ft_strcat:

The first loop is repeating work that could be handled by a call to size_str.

In ft_strjoin:

str = malloc(sizeof(char) * sizeall(size, strs, sep)));

sizeof (char) is uneccessary, as it is always 1. You need an additional 1 byte added to the length passed to malloc to make room for the NUL byte in your final string.

Remember that pointers are values too. str = strs[0]; assigns the pointer held in strs[0] to the the variable str. It does not copy the contents of strs[0]. You are overwriting the value returned by malloc with a pointer to a different piece of memory.

Instead, given this set of functions, initialize the memory returned by malloc to be the empty string, by setting the first byte to NUL, and use ft_strcat to concatenate the first string.

There's no need to continually reassign the result of ft_strcat, as you are already altering str, and the return value will never change.

A complete example. One must not forget to free the resulting string when it is no longer needed.

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

int size_str(char *str)
{
    int i = 0;

    while (str[i])
        i++;

    return i;
}

char *ft_strcat(char *dest, char *src)
{
    int i = 0,
        length = size_str(dest);

    do
        dest[length++] = src[i];
    while (src[i++]);

    return dest;
}

int size_all(int size, char **strs, char *sep)
{
    int total_length = size_str(sep) * (size - 1);

    for (int i = 0; i < size; i++)
        total_length += size_str(strs[i]);

    return total_length;
}

char *ft_strjoin(int size, char **strs, char *sep)
{
    char *result = malloc(1 + size_all(size, strs, sep));
    result[0] = '\0';

    ft_strcat(result, strs[0]);

    for (int i = 1; i < size; i++) {
        ft_strcat(result, sep);
        ft_strcat(result, strs[i]);
    }

    return result;
}

int main(void)
{
    char *sep = "   ";
    char a1[] = "Batata";
    char a2[] = "frita";
    char a3[] = "\'e";
    char a4[] = "melhor";
    char a5[] = "que";
    char a6[] = "Banana";
    char *strs[] = {a1, a2, a3, a4, a5, a6};
    char *final = ft_strjoin(6, strs, sep);

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

    free(final);
}

Output:

Batata   frita   'e   melhor   que   Banana
Oka
  • 23,367
  • 6
  • 42
  • 53
  • "causing an off-by-one error with your string lengths" But when I run it it shows the full thing. as when I take the -1 off, what is happening?--- And In ft_strjoin I'm not casting to anything the other comment is. --- I don't quite understand what you mean by: There's no need to continually reassign the result of ft_strcat, as you are already altering str, and the return value will never change. I call it several times so it can add the next word to the previous string---Do I need to finish it off with a "\0"? – MiguelP Jul 22 '21 at 01:39
  • @MiguelP My mistake on the casting comment. Try testing your `size_str` function, in isolation, because with your implementation `printf("%d\n", size_str("hello"));` will show `4`, not `5`. If your program manages to work despite this, it is just luck, as your resulting memory will be too small, and writing past the end of a block of memory causes [undefined behavior](https://en.cppreference.com/w/c/language/behavior), wherein *anything* can happen. – Oka Jul 22 '21 at 01:48
  • So just fixing that fixes the memory issue? – MiguelP Jul 22 '21 at 01:54
  • Fixing that, and making sure to allocate one more byte for the resulting string's NUL terminating byte is enough to fix the memory issues. As for the second question: `str` never changes its address, it always points to the same base address of the block of memory you allocated, and `ft_strcat` alters this memory by writing more to the end of the string it contains each time. `ft_strcat` already places `'\0'` after each call, including the last call of course. – Oka Jul 22 '21 at 01:56