Search code examples
cstrtokstrcat

Function strtok() does not work with strcat() (illegal hardware instruction)


I'm new at c and I'm writing a script that inputs a file path as arguments. I want to have the last element of the path and the rest of the path.

Here is what I wrote:

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

int main(int argc, char *argv[])
{
    char *file = argv[1];

    char base[sizeof(file)] = "";
    char *tok = strtok(file, "/");

    while (tok != NULL) 
    {
        strcat(base, tok);
        tok = strtok(NULL, "/");
    }

    printf("Base folder: %s\n", base);
    printf("Last element: %s\n", tok);

    return 0;
}

Input: ./getlast /this/is/some/path/file.txt

Expected result:

Base folder: /this/is/some/path
Last element: file.txt

It gives me this error when I concatenate base with tok:

[1]    15245 illegal hardware instruction  ./getlast /Users/<myusername>/Desktop/getlast/getlast.c

I keep trying different solutions but I can't figure out what is wrong.

(I haven't a good English so sorry for that)


Solution

  • To use strtok() for this task would be complicated. Determining which is the last token (filename) involves not commiting to concatentating until the next token is retrieved from the string.

    One could 'hang onto' one pointer and append when another token is found, but that's confusing.

    To find what might be called "the last token", strrchr() is perfectly suited to the task.

    I regard "enviroment vars" (like argv) to be readonly, so strdup() makes a working copy that can be altered with impunity.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void main( int argc, char *argv[] ) {
    
        if( argc != 2 ) { // always test before using
            printf( "Bad usage\n" );
            return;
        }
    
        char *copy = strdup( argv[1] ); // temp working copy to manipulate
        char *lastSep = strrchr( copy, '/' ); // find LAST slash char
    
        if( lastSep == NULL )
            printf( "No prefix path: %s\n", argv[1] );
        else {
            *lastSep++ = '\0'; // split into two strings
            printf( "Base folder: %s\n", copy );
            printf( "Last element: %s\n", lastSep );
        }
        free( copy );
    }
    

    Update You can avoid the overhead of making a working copy by capitalising on some pointer arithmetic and printf()'s length specifiers. Here's another way to achieve the same thing without using the heap:

    char *p = "/one/two/three/four.txt";
    
    char *lastSep = strrchr( p, '/' ); // find LAST slash char
    
    if( lastSep == NULL )
        printf( "No prefix path: %s\n", p );
    else {
        printf( "Base folder: %.*s\n", lastSep - p, p );
        printf( "Last element: %s\n", lastSep + 1 );
    }