0

I have to do an exercise and I have this structure given:

typedef struct {
    char *str;
    unsigned int len;
} String;

My Task is to write a String Concat which concats "Kartoffel" and "puffer" to "Kartoffelpuffer" (potato fritter).

String concat(String l, String r)

Both Strings l and r should not be changed after running the function. First I created the two Strings in the main:

String1 *l = malloc(sizeof(String1));
String1 *r = malloc(sizeof(String1));
(*l).str = malloc(sizeof("Kartoffel"));
(*r).str = malloc(sizeof("puffer"));
(*l).str = "Kartoffel";
(*r).str = "puffer";
(*l).len = 9;
(*r).len = 6;

Then I wrote the concat function:

String1 concat(String1 l, String1 r) {
    unsigned int i = 0;
    String1 *newStr = malloc(sizeof(String1));
    /* +1 for '\0' at the end */
    newStr->str = malloc(l.len + r.len + 1);
    newStr->str = l.str;
    /* The following line is not working */
    newStr->str[l.len] = *r.str;
    newStr->len = l.len + r.len;
    return *newStr;
}

What Im trying to do is working with pointer arithmetic. When there is a pointer which points to the beginning of a storage area like char *str, it should be possible to move the pointer with a[b] or *((a) + (b)) right? When I run the code I get Segmentation fault (I hope its the right translation. Original: "Speicherzugriffsfehler"). If someone could give me a hint I would be thankful. PS: Sorry for my English.

2
  • So I also need to write a function which copies from one storage area to another? Commented Jan 13, 2019 at 16:55
  • return *newStr; leaks memory, too. Commented Jan 13, 2019 at 17:06

3 Answers 3

2

First, (*l).str = "Kartoffel"; makes (*l).str point to the "Kartoffel" string literal, meaning that the original memory allocated to (*l).str with malloc() is lost. Same for (*r).str = "puffer";. One of the things you can do to avoid this is copy the string into the allocated buffer by looping over the characters in a for loop (since you can't use string.h).

Then, in your concat() function, you do the same thing. You allocate the memory for newStr->str with malloc() (properly allocating an extra char for the null-terminator), but on the next line you re-assign that pointer to point to l.str, which is still pointing to the string literal. Then, with newStr->str[l.len] = *r.str; you are attempting to modify the string literal, which in C is undefined behavior.

The way to fix this could be, again, to copy the two strings into the buffer allocated with newStr->str = malloc(l.len+r.len+1);.

Sign up to request clarification or add additional context in comments.

Comments

1

After allocating memeory to newStr and newStr->str
Two pointers could be used. char *to, *from;
Set the pointers with to = newStr->str; and from = l.str;
copy the characters with *to = *from;
Advance the pointers with to++; and from++;
Repeat until *from == 0
Set from with from = r.str;
to does not need to be reset as it is correctly positioned at the end of newStr->str.
Repeat the copy of characters.
Repeat advancing the pointers.
Set a terminating 0 with *to = 0;

Comments

1

Thank you very much for your help! I wrote another method to copy the string as you guys said.

char * copyStr (char * dest,char * src){
    unsigned int index;
    for (index = 0; src[index] != '\0'; index++) {
            dest[index] = src[index];
    }
    dest[index] = '\0';
    return dest;
}

And I edited my concat like that:

String1 concat (String1 l, String1 r){
    String1 *newStr = malloc(sizeof(String1));
    newStr->str = malloc(l.len+r.len+1);
    copyStr(newStr->str,l.str);
    copyStr((newStr->str+l.len),r.str);
    newStr->len = l.len+r.len;
    return *newStr;
}

with newStr->str+l.len the pointer will be moved. If l.len is 9, the pointer will point to the 10th byte, which is the end of the first string l. So the the String r will be copied in the memory storage behind the first string l.

1 Comment

Looks good, except that return *newStr; leaks memory: newStr is copied to the returned object, but then information about the original pointer is lost. It is better to return a String1* instead, so you can free the object when you're done with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.