Thread: returning an array of pointers

  1. #1
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242

    returning an array of pointers

    Hi all.

    Why is the compiler giving the below warning, and then the program crashes? Does this have something to do with pointers to pointers?

    Thanks in advance.

    Code:
    main.c|19|warning: return from incompatible pointer type [enabled by default]
    Code:
    #include <stdio.h>
    
    char * func(void);
    
    int main(void)
    {
        int ctr;
        char * array;
    
        array = func();
        for(ctr = 0; ctr < 3; ctr++)
            printf("%s\n", array[ctr]);
        return 0;
    }
    
    char * func(void)
    {
        static char * array[3] = { "one", "two", "three"};
        return array;
    }
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  2. #2
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Code:
    char * array[3];
    This declaration means that you create an array of size three that has as elements pointers to char! In other words it's an array of char pointers, thus the compiler warns you correctly.. You should have in line 8 char** array and not char* array.

    Also notice that you tried to run the code even by not eliminating the warning.Never ignore the warnings , especially in pointers

  3. #3
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    I changed line 3, 8 and 16 to char **, and it works now. Thanks.
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  4. #4
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Well, I am trying to apply this to my main program below, and I am still getting this particular type of warning when trying to return an array of pointers. Where does the problem lie in this situation? Thank you.

    Code:
    main.c|149|warning: return from incompatible pointer type [enabled by default]|
    Code:
    // getlinks: get URLs from a forum
    
    #include <curl/curl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define URL_LENGTH 150
    
    struct MemoryStruct {
        char *memory;
        size_t size;
    };
    
    static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp);
    char ** GetLinks(struct MemoryStruct datastruct);
    
    int main(void)
    {
        curl_global_init(CURL_GLOBAL_ALL);
    
        CURL *myhandle;
        CURLcode result;
        struct MemoryStruct datastruct;
    
        datastruct.memory = malloc(1); // will be grown as needed by realloc
        datastruct.size = 0; // no data at this point
        if((myhandle = curl_easy_init()) == NULL)
        {
            perror("curl_easy-init error");
            exit(EXIT_FAILURE);
        }
        if((result = curl_easy_setopt(myhandle, CURLOPT_URL, "http://cboard.cprogramming.com/c-programming/")) != CURLE_OK)
        {
            perror("CURLOP_URL error");
            exit(EXIT_FAILURE);
        }
        if((result = curl_easy_setopt(myhandle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback)) != CURLE_OK)
        {
            perror("CURLOPT_WRITEFUNCTION error");
            exit(EXIT_FAILURE);
        }
        if((result =  curl_easy_setopt(myhandle, CURLOPT_WRITEDATA, &datastruct)) != CURLE_OK)
        {
            perror("CURLOPT_WRITEDATA error");
            exit(EXIT_FAILURE);
        }
        if((result = curl_easy_perform(myhandle)) != 0)
        {
            perror("curl_easy_perform error");
            exit(EXIT_FAILURE);
        }
        curl_easy_cleanup(myhandle);
        GetLinks(datastruct);
        return 0;
    }
    
    static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
    {
        size_t realsize = size * nmemb;
        struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
        mem->memory = realloc(mem->memory, mem->size + realsize + 1);
        if (mem->memory == NULL) /* out of memory! */
        {
            printf("not enough memory (realloc returned NULL)\n");
            exit(EXIT_FAILURE);
        }
        memcpy(&(mem->memory[mem->size]), contents, realsize);
        mem->size += realsize;
        mem->memory[mem->size] = 0;
        return realsize;
    }
    
    char ** GetLinks(struct MemoryStruct datastruct)
    {
        char * temp_string;
        char * memory_copy;
        char * match; // pointer to search match;
        int location; // location of search match;
        static char ** links[100];
        char *search_string = "http://cboard.cprogramming.com/c-programming/";
        int ch; // test character
        int array_ctr = 0, len_memory_string, len_search_string, len_temp_string, ctr = 0, url_buffer_ctr = 0;
    
        len_memory_string = strlen(datastruct.memory);
        if((memory_copy = malloc(len_memory_string * sizeof(char) + 1)) == NULL)
        {
            perror("Memory allocation error");
            exit(EXIT_FAILURE);
        }
        strcpy(memory_copy, datastruct.memory);
        len_search_string = strlen(search_string);
        while((match = strstr(memory_copy, search_string)) != NULL)
        {
            location = match - memory_copy;
            len_temp_string = strlen(datastruct.memory) - (location + len_search_string + 1); // +1 to include " char
            if((ch = datastruct.memory[location + len_search_string]) == '"')
            {
                if((temp_string = malloc(len_temp_string * sizeof(char) + 1)) == NULL)
                {
                    perror("Memory allocation error");
                    exit(EXIT_FAILURE);
                }
                strcpy(temp_string, &datastruct.memory[location + len_search_string + 2]); // +2 to move past the " char
                if((memory_copy = realloc(memory_copy, len_temp_string + 1)) == NULL)
                {
                    perror("Memory allocation error");
                    exit(EXIT_FAILURE);
                }
                strcpy(memory_copy, temp_string);
                continue;
            }
            else
            {
                while((ch = memory_copy[location]) != '"')
                {
                    if((links[array_ctr] = malloc(URL_LENGTH * sizeof(char))) == NULL) // allocate memory for pointer to hold URL
                    {
                        perror("Memory allocation error");
                        exit(EXIT_FAILURE);
                    }
                    *links[array_ctr][url_buffer_ctr] = ch;
                    location++;
                    url_buffer_ctr++;
                }
                links[array_ctr][url_buffer_ctr] = '\0';
                puts(*links[0]);
                array_ctr++; // increment array to accept new URL
                url_buffer_ctr = 0; // reset
                location++; // move past "
                len_temp_string = strlen(memory_copy) - location; // the rest of memory_copy after the "
                if((temp_string = realloc(temp_string, len_temp_string + 1)) == NULL)
                {
                    perror("Memory allocation error");
                    exit(EXIT_FAILURE);
                }
                strcpy(temp_string, &memory_copy[location]);
                if((memory_copy = realloc(memory_copy, len_temp_string + 1)) == NULL)
                {
                    perror("Memory allocation error");
                    exit(EXIT_FAILURE);
                }
                strcpy(memory_copy, temp_string);
                continue;
            }
            free(memory_copy);
            free(temp_string);
            return links;
        }
    }
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  5. #5
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Ok, I think this fixes the problem.

    Code:
    char ** GetLinks(struct MemoryStruct datastruct)
    {
        char * temp_string;
        char * memory_copy;
        char * match; // pointer to search match;
        int location; // location of search match;
        static char * links[100];
    .
    .
    .
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  6. #6
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Yes, but you have to understand why..
    When you have the declaration
    Code:
    char * links[100];
    this would be (almost) equivalent to a double pointer of chars (char**) .
    Here we have an array (which fetch us the first asterisk) and then we have as elements of the array char pointers(which fetch as the second asterisk).

    When you have the declaration
    Code:
    char ** links[100];
    this would be (almost) equivalent to a triple pointer of chars (char***) .
    Here we have an array (which fetch us the first asterisk) and then we have as elements of the array double char pointers(which fetch as the second and third asterisk).

    In usual single and double pointers are the useful ones.

    But i do not get why you use the static keyword and not dynamically allocating the array? Because the size is fixed?? I am just asking because whenever i see code doing this, it does it with malloc.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    It's nowhere near as complicated as std190003 says.

    char *links[100]; is 100 pointers to char stored in a row.
    char **links[100]; is 100 pointers to pointers to char stored in a row.
    In both cases the elements are pointers and the storage requirements for arrays (as opposed to char ** or char *** respectively) are different. Arrays and pointers are thus not the same. Question 6.2

  8. #8
    Registered User
    Join Date
    Jul 2012
    Location
    Australia
    Posts
    242
    Quote Originally Posted by std10093 View Post

    But i do not get why you use the static keyword and not dynamically allocating the array? Because the size is fixed?? I am just asking because whenever i see code doing this, it does it with malloc.
    I am sort of dynamically allocating the array. I know that the array will have less than 100 hundred elements, so I set the index to be 100. And then I dynamically allocate memory for each new required element in the array. So if there are only 23 elements that need to be used, memory will be allocated for only 23 elements. Just because the index is 100 does not mean that memory will be allocated to all 100 elements, and that some elements will be unused. So there is no wasted memory.

    But I wrote this code late at night, so my logic at that time is probably not the best. And have not had time to debug it yet.

    Code:
    static char * links[100];
    Code:
    links[array_ctr] = malloc(URL_LENGTH * sizeof(char))) == NULL) // allocate memory for pointer to hold URL
    IDE: Code::Blocks | Compiler Suite for Windows: TDM-GCC (MingW, gdb)

  9. #9
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    The malloc seems ok.

    Let me argue on the field about memory.You will not store memory for where the unused char pointes point to... But this means that there is memory that does not really be used by you..The char pointers are already created, thus they consume memory (well maybe not so much memory, because usually the size of char is equal to one, but isn't it beautiful to select the optimal settings for the space and time complexity of your code) .
    So yes i agree that you do not allocate memory for all your pointers, but you allocate memory for the pointers themselves...As a result even if you use== you malloc only one string,still you will have 99 pointers there, stored in your memory and do nothing...

    The max size can be 100...But the minimum size can be 1... But you do not really know the exact size .. Here comes the elegant simple linked list to meets your needs.Of course a bit more complex than array and also introduces the latency you get to traverse to the i-th element where in the array you just access the i-th element instantly.

    Maybe i am overreacting because the numbers are obviously small... But it is a chance to practice , so that when time comes to cope with 1.000.000.000 elements to fearlessly use lists!

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    The reason you see such code with malloc is because returning static memory is not particularly safe unless you know what you're doing. [edit] And you can always avoid returning a pointer to the first element of some array, by using an array argument. [/edit] You only have access to the one array allocated statically, in the scope of the function, so if you return pointers to that array, changes can be made by any pointer sharing the region. So they have to be treated like globals. In a threaded environment they also have to be treated like globals.

    At the moment, I think cfanatic's scheme is a good stopgap while he works out bigger things in his program. Before he releases his code, he should throw in a malloc() (and a free()) though. While linked lists are great, I think you only really need them in the situation where, if you used an array, you would be stuck figuring out how to remove things in the middle. Fast insertion and deletion is one of the best benefits of lists, and probably the most important one. It may not be the most efficient use of space, but 400 bytes is far from the end of the world today.
    Last edited by whiteflags; 11-19-2012 at 09:37 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Returning a Dynamic array of pointers
    By smhillis in forum C Programming
    Replies: 14
    Last Post: 08-02-2009, 12:27 AM
  2. Parsing and returning array pointers?
    By thealmightyone in forum C Programming
    Replies: 26
    Last Post: 03-26-2009, 03:38 PM
  3. Returning pointer to array of pointers problem
    By jimzy in forum C Programming
    Replies: 15
    Last Post: 11-11-2006, 06:38 AM
  4. Returning an Array of Pointers to Objects
    By randomalias in forum C++ Programming
    Replies: 4
    Last Post: 04-29-2006, 02:45 PM
  5. returning an array of pointers to structures
    By dharh in forum C Programming
    Replies: 9
    Last Post: 02-06-2003, 03:26 PM