f1a2j3n
f1a2j3n

Reputation: 21

strlen() crashes when I call it

I am trying to write a simple piece of code that merges two strings together in even and odd indexes.

This is the code

void two_strings(char a[], char b[]) {
    int counta = 0, countb = 0;
    int lena = strlen(a); 
    int lenb = strlen(b);
    int lenab = lena + lenb;
    char ans[lenab];
    for(int i = 0; i<strlen(ans); i++) {
        if(i%2 == 0) {
            ans[i] = a[counta];
            counta++;
        }
        else {
            ans[i] = b[countb];
            countb++;
        }
    }
    printf("%s\n", ans);
}

This is the main:

int main() {   
    char a[] = "hello";
    char b[] = "bye";
    two_strings(a, b);
    return 0;
}

I have compiled it with -Wall and didn't get any warnings or errors, and I have tried it also with long instead of int just to check if that was the issue. when I run the code it doesn't get past the first strlen(a)

Upvotes: 1

Views: 924

Answers (1)

Oka
Oka

Reputation: 26345

Strings in C are defined as a sequence of non-null bytes followed by a terminating null byte ('\0').

The following are equivalent strings

char one[] = "hello";
char two[] = { 'h', 'e', 'l', 'l', 'o', '\0' };

Both of these would have a string length of 5, and occupy 6 bytes of memory.

String handling functions in the Standard Library expect this null-terminating byte, and you will invoke Undefined Behavior by passing a non-null-terminated array to them. strlen and printf (with %s) are examples of these kinds of functions.

In your two_strings function you are not allocating enough memory to store the null-terminating byte. You also make no attempt to place this null-terminating byte in the array.

Allocate an additional byte for the null-terminating byte, and do not attempt to take the string length of an uninitialized array.

void two_strings(char a[], char b[]) {
    /* ... */

    size_t length = strlen(a) + strlen(b);
    char string[length + 1];
    
    for (size_t i = 0; i < length; i++) {
        /* ... */
    }

    string[length] = '\0';

    /* ... */
}

Also note that size_t is the correct type to use when dealing with memory indexing, and is the type returned by strlen.


As for your algorithm, in the event where your input strings differ in length you will attempt to continue indexing one of the strings after you have already reached its end.

You will either want to: only take the smaller string's length of characters from the larger string, stopping when the smaller string has been exhausted; or, append the remaining characters of the larger string to the result after the smaller string has been exhausted.

A quick example of the second approach:

#include <stdio.h>
#include <string.h>

void zip_strings(const char *a, const char *b) {    
    size_t combined_length = strlen(a) + strlen(b);
    char joined_string[combined_length + 1];
    
    for (size_t i = 0; i < combined_length; i++) {
        const char **src = i & 1 ? &b : &a;

        if (!**src)
            src = &a;
        if (!**src)
            src = &b;

        joined_string[i] = *((*src)++);
    }
    
    joined_string[combined_length] = '\0';

    puts(joined_string);
}

int main(int argc, char **argv) {
    if (argc > 2)
        zip_strings(argv[1], argv[2]);    
}
./a.out hello computer
hceolmlpouter

Upvotes: 4

Related Questions