0

I'm trying to write a fast function for filtering a char ** and putting the results into another char **

This is what I have written:

/*
   -filterable is what is to be filtered
   -filter is the filter
   -filtered is the result applying the filter to filterable
*/
void filter(const char** filterable,const char * filter,char** filtered)
{
    memset(filtered,'\0',sizeof(filtered));
    int i=0;
    int j=0;
    int filter_length=strlen(filter);
    int items=sizeof(filterable)/sizeof((char *) filterable); //segfault?

    while(items--)
    {
        if((strncmp(filter,filterable[i],filter_length)==0))
            strcpy(filtered[j++],filterable[i]);

        i++;
    }
}

The issue is I don't think I'm getting the number of rows from "filterable" properly as I'm getting a segfault. Any suggestions? Is this the fastest approach to filtering a char **?

Post-Comments:

Okay I read everyone's comments and the below seems to be working. Given this needs to be fast I threw in the register keyword although I've heard it doesn't guarantee anything these days.

void filter(char ** filterable, const char * filter, char ** filtered, int filters)
{
    register int i=0;
    register int j=0;
    int filter_length=strlen(filter);

    while(filters--)
    {
        if((strncmp(filter,filterable[i],filter_length)==0))
           strcpy(filtered[j++],filterable[i]);

        i++;
    }
}
jparanich
  • 8,372
  • 4
  • 26
  • 34
  • 1
    bad usage of `sizeof`. You're passing a pointer as argument to the operator `sizeof`. You need to pass the size in function arguments. – pmg Mar 31 '11 at 14:29
  • 2
    As this quetion is tagged C++, do you have any reason not to use C++ containers here, instead of raw buffers ? i.e: std::vector – Jem Mar 31 '11 at 14:35
  • `sizeof(filterable)/sizeof((char *) filterable)` is always 1, since pointer to `char**` and to `char*` have the same size. If you want to know the number of elements in filterable, pass it as an argument to the function. – Thalur Mar 31 '11 at 14:43
  • @Jem: This is nestled in C++ code, but I want to re-use it in ansi C at some point. I removed the tag. Thx. – jparanich Mar 31 '11 at 15:22

3 Answers3

2

You can't use sizeof(char**) (as the function actually receives), see this SO Question. You should give the length of the array as a parameter to the function.

Community
  • 1
  • 1
MByD
  • 135,866
  • 28
  • 264
  • 277
2

You've confusing pointers, arrays, and what pointers point to.

memset(filtered, '\0', sizeof(filtered)); is probably giving you the segfault. filtered is of type char **, which means that sizeof(filtered) is the size of a pointer, not anything pointed at, and you're setting filtered, which is a pointer to char *, to zero. This is undefined behavior, but on most modern computers sets filtered to the null pointer. You need to have memory allocated for what filtered points to, and what those char * point to, and you need to pass in how big filtered is and how big the string areas it points to are.

Since filtered contains an invalid memory address, trying to strcpy() anything to it or anything it ostensibly points to will try to access it, and that will normally give you a segfault on a Unix/Linux machine.

sizeof(filterable)/sizeof(char *) filterable) does nothing useful. If filterable was an array, sizeof(filterable)/sizeof(*filterable) would give you the number of elements in filterable. However, even if it was originally an array, it's passed as a pointer, and has lost all information about the number of elements it contains.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
0

sizeof(filtered) is going to be 4 on the usual 32-bit machine. That is, sizeof(char**) == 4. Is that what you are looking for when you call memset( filtered,'\0',sizeof(filtered) ) ?

The segfault just might be arising from the fact that filtered == 0x0000 after you call memset().

-- pete

Pete Wilson
  • 8,610
  • 6
  • 39
  • 51