Thread: Multidimensional arrays returning.

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    242

    Multidimensional arrays returning.

    Well, actually I'm trying to create a program that receives strings from a file and replaces a few words from some kind of a source (another file) and swap between words that are in the source of the words.
    These words are shown this way in the file:
    Code:
    elephant fat
    mouse thin
    smart stupid
    and in the original file there are strings, such as:
    Code:
    This guy is really smart!
    So now, I'm trying to receive the data from the strings-file and swap words that are shown in the source file and create a new sentence by swapping these words.
    e.g:
    original file:
    Code:
    You are smart
    After compiling:
    Code:
    You are stupid.
    Here's what I've got so far:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    #define LENGTH 50
    
    char *newSubstr(char *str, int index);
    char **explode(char *str, char seperator);
    
    int main(void)
    {
        FILE *handle, *db;
        char *filename, str[LENGTH];
        
        printf("File: ");
        fgets(filename, 16, stdin);
        
        handle = fopen(filename, "rt");
        db = fopen("database.txt", "rt");
        
        while(fgets(str, LENGTH, handle) != NULL)
        {
                         for(int i = 0; i < strlen(str); i++)
                         {
                                if(str[i] == ' ' && i + 1 < strlen(str))
                                {
                                          char search[LENGTH], **results;
                                           while(fgets(search, LENGTH, db) != NULL)
                                           {
                                                      results = explode(search, ' ');
                                                      if(strcmp(results[0], newSubstr(str, i+1)) == 0) // if equals, swap the string with results[1]
                                                                            printf("Match! &#37;s - %s", results[0], results[1]);                                                               
                                           }
                                }
                         }                          
        }
        
     getchar();
     return 0;   
    }
    
    char *newSubstr(char *str, int index)
    {
     int i = index, j= 0;
     char *newstr = "";
     
     for(; i < strlen(str); i++)
     {
           if(str[i] == ' ')
                     break;
           newstr[j++] = str[i]; 
     }
                    
     return newstr;
    }
    
    
    char **explode(char *str, char seperator) // explodes ONLY 2 strings that are seperated by a character
    {
         int i = 0, index = 0;
         for(; i < strlen(str); i++)
               if(str[i] == seperator)
                         break;
         
         char **newexplode;
         if(i != 0 && i != strlen(str) - 1)
         {
            int index_0 = 0, index_1 = 0;
            int j = 0;
            for(; j < i; j++)
               newexplode[0][index_0++] = str[j];                          
            for(; i < strlen(str); i++)
               newexplode[1][index_1++] = str[i];                           
         }
         
         return newexplode;
    }

    I'm pretty sure (actually, I know) that there is a problem with the return values of `explode` and `newSubstr`...I dunno, look at this code for example:
    Code:
    char *newSubstr(char *str, int index)
    {
     int i = index, j = 0;
     char newstr[20];
     
     for(; i < strlen(str); i++)
     {
           if(str[i] == ' ')
                     break;
           newstr[j++] = str[i]; 
     }
                    
     return newstr;
    }
    
    int main(void)
    {
        char *str = newSubstr("Hello world", 6);
    	printf("%s", str);
        getchar();
     return 0;   
    }
    Really basic but still, `str` contains total garbage, and I don't know why...



    It's pretty basic what I've done here so please help me ASAP (these are just pointers and return values, come on )
    Last edited by eXeCuTeR; 06-30-2008 at 05:31 PM.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    >>char **newexplode;
    >>newexplode[0][index_0++] = str[j];
    You never allocate any memory for newexplode.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    The larch
    Join Date
    May 2006
    Posts
    3,573
    It seems that you are nowhere allocating memory for the exploded strings?
    And anyway, there is the strtok function that might be suitable for splitting strings.

    In newSubstr you are returning a pointer to a local array. The problem with local arrays is that they go out of scope and the pointer is not valid once the function returns. (In addition newstr doesn't appear to get 0-terminated.)
    Usually it is just easier to pass the buffer that receives output as an argument. Think about strcpy: it doesn't allocate any new memory, it copies to the provided buffer.
    Last edited by anon; 06-30-2008 at 05:30 PM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  4. #4
    Registered User
    Join Date
    Oct 2007
    Posts
    242
    > Elysia, Why do I need to allocate memory for `newexplode`?
    > anon, Why I'm supposed to 0-terminate newstr?
    Usually it is just easier to pass the buffer that receives output as an argument. Think about strcpy: it doesn't allocate any new memory, it copies to the provided buffer.
    What do you mean?

  5. #5
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Quote Originally Posted by eXeCuTeR View Post
    >
    > anon, Why I'm supposed to 0-terminate newstr?

    What do you mean?
    Strings in C must be terminated with the '\0' character. This is the way how any function such as strlen or printf can actually know where the string ends.

    As to how newSubstr could be implemented:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    void newSubstr(char* output, const char *str, int index)
    {
        int i = index, j = 0;
    
        /*strlen is a bit too expensive to call each time in a loop*/
        int length = strlen(str);
    
        for(; i < length; i++)
        {
            if(str[i] == ' ')
                break;
            output[j++] = str[i];
        }
        /*null-terminate the output string*/
        output[j] = '\0';
    }
    
    int main(void)
    {
        /*declare the array that receives the substring and pass it to newSubstr*/
        char str[20];
        newSubstr(str, "Hello world", 6);
    	printf("%s", str);
        getchar();
     return 0;
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #6
    The larch
    Join Date
    May 2006
    Posts
    3,573
    As to why you need to allocate memory for newexplode: if you don't make it to point to some memory, the pointer will point to random garbage and you'd end up trying to write to a random place in memory that your program might not own.

    However, it is not easy to allocate (and free) two-dimensional arrays.

    Instead you might simply modify the original string, taking advantage of how strings are represented in C, and return a pointer that points in the middle of the original string where the second word begins.

    Code:
    original string:
    'm','o','u','s','e',' ','t','h','i','n','\0'
     ^
     |
    str
    
    after splitting:
    'm','o','u','s','e','\0','t','h','i','n','\0'
     ^                        ^
     |                        |
    str                    start of
                          second word
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  7. #7
    Registered User
    Join Date
    Oct 2007
    Posts
    242
    Quote Originally Posted by anon View Post
    Strings in C must be terminated with the '\0' character. This is the way how any function such as strlen or printf can actually know where the string ends.

    As to how newSubstr could be implemented:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    void newSubstr(char* output, const char *str, int index)
    {
        int i = index, j = 0;
    
        /*strlen is a bit too expensive to call each time in a loop*/
        int length = strlen(str);
    
        for(; i < length; i++)
        {
            if(str[i] == ' ')
                break;
            output[j++] = str[i];
        }
        /*null-terminate the output string*/
        output[j] = '\0';
    }
    
    int main(void)
    {
        /*declare the array that receives the substring and pass it to newSubstr*/
        char str[20];
        newSubstr(str, "Hello world", 6);
    	printf("&#37;s", str);
        getchar();
     return 0;
    }
    As I've heard, C automatically 0-terminates arrays, doesn't it?
    Anyways,
    I've got 1 questions:
    Why do local arrays go out of scope if they are returned as pointers?
    As for explode...I've tried to implement it this way:
    Code:
    void explode(char *str, char seperator, char **match) // explodes ONLY 2 strings that are seperated by a character
    {
         char first[20], second[20];
         int i = 0, index = 0;
         for(; i < strlen(str); i++)
               if(str[i] == seperator)
                         break;
         
         if(i != 0 && i != strlen(str) - 1)
         {
            int index_0 = 0, index_1 = 0;
            int j = 0;
            for(; j < i; j++)
               first[index_0++] = str[j];                          
            for(; i < strlen(str); i++)
               second[index_1++] = str[i];    
               
            strcpy(match[0], first);
            strcpy(match[1], second);                       
         }
    }
    But it's not working properly.
    Why?

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Quote Originally Posted by eXeCuTeR View Post
    As I've heard, C automatically 0-terminates arrays, doesn't it?
    Yes, library functions do that. But if you manipulate individual characters yourself, you have to take care of terminating strings.
    Anyways,
    I've got 1 questions:
    Why do local arrays go out of scope if they are returned as pointers?
    That's because they are local. You would be returning a pointer to something that doesn't exist after the function returns.

    As for explode...I've tried to implement it this way:
    ...snip...

    But it's not working properly.
    Why?
    For one thing, you are still not terminating the new strings.

    For another thing, which can't be seen from this code: have you allocated any memory for match in the calling code (and how)?

    Anyway, you might take a look at my previous post to see how the same thing could be done without allocating any new strings.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Registered User
    Join Date
    Oct 2007
    Posts
    242
    Quote Originally Posted by anon View Post
    Yes, library functions do that. But if you manipulate individual characters yourself, you have to take care of terminating strings.

    That's because they are local. You would be returning a pointer to something that doesn't exist after the function returns.


    For one thing, you are still not terminating the new strings.

    For another thing, which can't be seen from this code: have you allocated any memory for match in the calling code (and how)?

    Anyway, you might take a look at my previous post to see how the same thing could be done without allocating any new strings.
    Oh right, forgot to 0-terminate.
    ---
    I haven't allocated any memory to any array, I have just called it this way, which seems totally cool for me:
    Code:
        char *newarr[2];
        explode("Hello world", ' ', newarr);
        printf("&#37;s [ ~ ] %s", newarr[0], newarr[1]);

    I would like to hear the way to do this by allocating memory and the other way.
    Last edited by eXeCuTeR; 06-30-2008 at 06:47 PM.

  10. #10
    The larch
    Join Date
    May 2006
    Posts
    3,573
    It may look cool to you but it is still nothing more than an array of two pointers to garbage.

    It should look something like this:
    Code:
    int main()
    {
        char *newarr[2];
        newarr[0] = malloc(20);
        newarr[1] = malloc(20);
        explode("Hello world", ' ', newarr);
        printf("&#37;s [ ~ ] %s", newarr[0], newarr[1]);
        free(newarr[0]);
        free(newarr[1]);
        return 0;
    }
    However, if you just modified the original string in place (as my ASCII art shows) it might be implemented like this (you can roll your own if you are not allowed to use library functions).
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    char* explode(char* str, const char* separator)
    {
        char* second = strtok(str, separator);
        if (second != NULL) {
            second = strtok(NULL, separator);
        }
        return second;
    }
    
    int main()
    {
        char str[] = "Hello world";
        char* second = explode(str, " ");
        printf("%s [ ~ ] %s", str, second);
        return 0;
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  11. #11
    Registered User
    Join Date
    Oct 2007
    Posts
    242
    It works good now with the memory allocation.
    Why can't I do this thing:
    Code:
    char *arr[2] = (char *)malloc(40);
    I should allocate memory to each pointers(or ARRAYS) I use (in case he is not pointing to any variable)? I'm assuming that yes since pointers that are not initialized point to a random memory address.
    Last edited by eXeCuTeR; 06-30-2008 at 08:00 PM.

  12. #12
    Registered User
    Join Date
    Oct 2007
    Posts
    242
    If anyone is interested...
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define LENGTH 80
    
    void explode(char *str, char seperator, char **match, int index1, int index2) // explodes ONLY 2 words that are seperated by a character
    {
         int i = 0, index = 0;
         for(; i < strlen(str); i++)
               if(str[i] == seperator)
                         break;
         
            int index_1 = 0, index_2 = 0;
            int j = 0;
            for(; j < i; j++)
               match[index1][index_1++] = str[j];  
            i++;                        
            for(; i < strlen(str); i++)
            {
               if(str[i] == '\n')
                         break;
               match[index2][index_2++] = str[i]; 
            }
                   
            match[index1][index_1] = '\0';
            match[index2][index_2] = '\0';                    
    }
    
    void newSubstr(char* output, char *str, int index)
    {
        int i = index, j = 0;
    
        /*strlen is a bit too expensive to call each time in a loop*/
        int length = strlen(str);
    
        for(; i < length; i++)
        {
            if(str[i] == ' ' || str[i] == '\n')
                break;
            output[j++] = str[i];
        }
        /*null-terminate the output string*/
        output[j] = '\0';
    }
    
    int main(void)
    {
        FILE *handle, *db;
        handle = fopen("hi.txt", "r");
        db = fopen("database.txt", "r");
        
        int len = 0;
        char newDBstring[LENGTH], *results[LENGTH/2], str[LENGTH];
        
        for(int i = 0; i < LENGTH/2; i++)
                results[i] = (char *)malloc(LENGTH/2);
                 
        int index1 = 0, index2 = 1;
        while(fgets(newDBstring, LENGTH, db) != NULL)
        {
                                 explode(newDBstring, ' ', results, index1, index2);
                                 printf("&#37;s,%s\n", results[index1], results[index2]);
                                 index1 = index1 + 2, index2 = index2 + 2;
                                 len++;
        }
        
        while(fgets(str, 40, handle) != NULL)
        {
                         printf("\n%s\n", str);
                         for(int i = 0; i < strlen(str); i++)
                         {
                                 if(str[i] == ' ' || i == 0)
                                 {
                                           int index = 0;
                                           char *output = (char *)malloc(LENGTH);
                                           if(i == 0)
                                                newSubstr(output, str, i);
                                           else
                                               newSubstr(output, str, i+1);
                                           printf("Output: %s\n", output);
                                           for(int k = 0; k < len*2; k = k+2)
                                           {
                                                   if(strcmp(output, results[k]) == 0)
                                                                         printf("MATCH! %s = %s -> %s\n", output, results[k], results[k+1]);        
                                           } 
                                           free(output);
                                 }        
                         }                
        }
        fclose(handle);
        fclose(db);
        for(int i = 0; i < len; i++)
                free(results[i]);
        
        getchar();   
        return 0;
    }
    Last edited by eXeCuTeR; 06-30-2008 at 10:06 PM.

  13. #13
    Registered User
    Join Date
    Mar 2008
    Location
    India
    Posts
    147

    Is this Output correct ?

    The Output for your program is

    Code:
    smart,hard
    pass,fail
    
    You are smart
    
    Output:You
    Output:are
    Output:smart
    MATCH! smart = smart -> hard
    Is this is the same output which is as per design.

    I thought you must get like

    If it is

    Code:
    You are smart

    Code:
    You are stupid
    where database.txt is

    Code:
    smart stupid
    and hi.txt is

    Code:
    You are smart

  14. #14
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Quote Originally Posted by eXeCuTeR View Post
    It works good now with the memory allocation.
    Why can't I do this thing:
    Code:
    char *arr[2] = (char *)malloc(40);
    I should allocate memory to each pointers(or ARRAYS) I use (in case he is not pointing to any variable)? I'm assuming that yes since pointers that are not initialized point to a random memory address.
    I think you would write it like:
    Code:
    char (*arr)[2] = (char (*)[10])malloc(40);
    so you typecast in an appropriate thing. The other will not work, since *arr[2] isn't type of char*

  15. #15
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    char (*arr)[2] = (char (*)[10])malloc(40);
    I get an "initialization from incompatible pointer type" warning. And when I try it, it indeed doesn't do what I want.

    Since it is an array of 2 pointers, I believe you can't get away without two memory allocations (or assigning two pointers):
    Code:
    char* arr[2] = {malloc(20), malloc(20)};
    Code:
    const char* str = "Hello\0world";
    const char* arr[2] = { str, str + 6 };
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 0
    Last Post: 05-29-2009, 05:48 AM
  2. Multidimensional Arrays
    By jordanguyoflove in forum C Programming
    Replies: 4
    Last Post: 10-16-2008, 06:16 PM
  3. Multidimensional Arrays?
    By CreatedByShadow in forum C++ Programming
    Replies: 7
    Last Post: 01-13-2006, 10:35 PM
  4. Pointers to Multidimensional Arrays
    By kidburla in forum C Programming
    Replies: 10
    Last Post: 10-29-2005, 10:45 PM
  5. Multidimensional arrays in Korn shell
    By Yasir_Malik in forum Tech Board
    Replies: 3
    Last Post: 04-11-2004, 02:16 PM