tags:

views:

47

answers:

3

I'm trying to write a get file extension function in C.

This is what I have...

char *getFileExt(char *filename) {

    char ext[10];

    while (*filename) {
        filename++;
    }

    while (*filename != '.') {
        *(ext++) = *(--filename);               
    }   
    strrev(*ext);       
    return ext;     
}

I keep getting EXC_BAD_ACCESS on the line inside the while loop. I'm new with pointers, so my guess is I am doing something wrong with them.

Why can't I assign the filename pointer's value to ext?

Thanks

+2  A: 
char* getFileExt(char *filename)
{
    while (*filename) filename++;
    while (*filename != '.') --filename;                 
    return filename;     
}

Or version with non crash if filename not contains .

char* getFileExt(char *filename) 
{
    char* _ext = filename;
    while (*_ext) _ext++;
    while (_ext >= filename && *_ext != '.') --_ext;                
    if (_ext < filename) _ext = NULL;
    return ext;     
}
Svisstack
Does that first example return a pointer to the start of the file extension?
alex
The `_ext < filename` case relies on undefined behavior. http://c-faq.com/aryptr/non0based.html
bk1e
@bk1e: not, you don't have right, described other case in this link
Svisstack
When `filename` doesn't contain a `.`, `_ext` ends up pointing to `filename-1` for a moment, before it gets set to `NULL`. Unless `filename` points to the middle of a larger array, this is undefined behavior. In this case, `_ext` doesn't point to one of the array elements or to one element past the end; it points to one element below the beginning. On most platforms, this *happens* to work, but the C standard doesn't guarantee it: the final decrement of `_ext` could raise a CPU exception, the comparison of `_ext < filename` could return the wrong value, or something even stranger could happen.
bk1e
@bk1e: fixed, pointer after final decremental will be not followed, only address values of her will be comapred.
Svisstack
That's not what I was talking about, but you're right: on Windows or Linux, if `filename` pointed to the first byte of a page and the previous page was inaccessible, the previous version would have crashed. However, the C standard doesn't guarantee that you can even decrement the pointer past the beginning of `filename`.
bk1e
+5  A: 

You should never return a pointer of a local array. The array data is lost when the function loses scope and the pointer will be dangling.

Besides, you cannot change the value of the array pointer. This is why you're getting the EXC_BAD_ACCESS error. You can either use an integer index or a char * pointer which points to the first entry.

By the way: There's a function strrchr (see here) that gives you the last occurance of a character in a string. You can return that resulting pointer, because it points to a valid position in the filename array which is also valid outside the function.

+2  A: 

I keep getting EXC_BAD_ACCESS on the line inside the while loop.

while (*filename != '.') 
{
  *(ext++) = *(--filename);               
} 

above you are treating 'ext' as a pointer, however 'ext' is declared as an array if you want to use a pointer, then declare another pointer and point it to 'ext'

while (*filename) {
  filename++;
}

in the above while loop you are moving the pointer 'filename' until it lands on '\0' that's ok but instead you could start from the end of filename by position yourself on the last '.' like this:

char *p = filename + strlen( filename ) - 1; // last char

then move forward

while (*p != '.') --p;

now you p is where the '.' is

now copy from p + 1

strcpy( ext, p + 1 ); 

when you return you cannot return 'ext' because it doesn't exist outside the function body.

a way to do it is to either pass ext as an extra argument to the function where you allocate the 'ext' outside the function or use the heap allocate space for the extension

char *getFileExt(char *filename,char *ext)

or even better

char *getFileExt(char *filename,char *ext, size_t maxlen_ext)

or

char *getFileExt(char *filename)
{
   char* ext = malloc( 10 );
...
Anders K.