Thread: can you declare an array of unknown size

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    808

    can you declare an array of unknown size

    i have an array declared as 3 x 26 but only some of the elements are used (actually in this case 15)
    row 0 has 8 elements used
    row 1 has 2 elements used
    row 2 has 5 elements used

    i then create a string row 0 element 0 + row 1 element 0 + row 2 element 0
    then the next string created is row 0 element 0 + row 1 element 0 + row 2 element 1 and so on until the last string created is row 0 element 7 + row 1 element 1 + row 2 element 4 ie the last possible combination.

    In this case it makes 80 combinations but different inputs might make a different combination of combinations

    how can i create a versatile array that will hold any number of combinations

  2. #2
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    probably easier to see what i am banging on about if i post the code
    Code:
    int myfunc( char *, int, int , int , int );
    void PrintGuesses( int [][26], int );
    //void TestPossPword( char *, char *, int [][26], int );
    
    int main()
    {
        char text[] = "The quick brown fox jumps, over the lazy dog!";
        char pword[] = "hel";
        char encrypted[sizeof text];
    
        int len = strlen( text );
        int plen = strlen( pword );
    
        for ( int j = 0, i = 0; text[i]; i++, j = (j + 1) % plen )
            encrypted[i] = text[i] ^ pword[j];
        encrypted[len] = '\0';
    
        int Guesses[ sizeof pword - 1 ][26] = { 0 };
        // Don't use numbers for letters, e.g., say 'A' instead of 65.
        for ( int StartIndex = 0; StartIndex < plen; StartIndex++ )
        {
            int GuessIndex = 0;
    
            for ( int i = 'a'; i <= 'z'; i++ )
            {
                if ( myfunc( encrypted, i, StartIndex, len, plen ) )
                {
                    Guesses[StartIndex][GuessIndex] = i;
                    GuessIndex++;
                }
            }
            //putchar('\n');
        }
    
        PrintGuesses( Guesses, plen );
    
        //printf("%s\t%s\t%s\n", "1st", "2nd", "3rd");
    
        //TestPossPword( encrypted, pword, Guesses, plen );
        for ( int i = 0; Guesses[0][i] != 0; i++ ) //first letter
            for ( int j = 0; Guesses[1][j] != 0; j++ ) // second letter
                for ( int k = 0; Guesses[2][k] != 0; k++ ) //third letter
                {
                    char GuessedPword[sizeof pword ] = { '\0' };
    
                    GuessedPword[0] = Guesses[0][i];
                    GuessedPword[1] = Guesses[1][j];
                    GuessedPword[2] = Guesses[2][k];
    
                    printf("%d\t%d\t%d = %s\n", i, j, k, GuessedPword);
    
                    char Decrypted[sizeof encrypted] = { '\0' };
                    for ( int y = 0, x = 0; x < sizeof encrypted - 1; x++, y = (y + 1) % plen )
                    {
                        char c = encrypted[x] ^ GuessedPword[y];
                        Decrypted[x] = c;
                        printf("%c", Decrypted[x]);
                    }
                    putchar('\n');
                    if ( ( strstr( Decrypted, "The" ) != NULL ) || ( strstr( Decrypted, "the" ) != NULL ) )
                    {
                        printf("Password Found!!\n");
                        printf("Text = %s\n", Decrypted);
                    }
                }
    
        return 0;
    }
    
    int myfunc( char *Encrypted, int i, int StartIndex, int len, int plen )
    {
        int Letter = 1;
    
        for ( int j = StartIndex; j < len; j += plen )
        {
            int x = Encrypted[j] ^ i;
            if ( ! ( ( x >= 'A' && x <= 'Z' ) || ( x >= 'a' && x <= 'z' ) || (  x >= ' ' && x <= '@' ) ) )
            {
                Letter = 0;
                break;
            }
        }
        return Letter;
    }
    
    void PrintGuesses( int Guesses[][26], int plen )
    {
        for ( int i = 0; i < plen; i++ )
        {
            printf("%d  ", i);
            for ( int j = 0; j < 26; j++ )
            {
                if ( Guesses[i][j] == 0 )
                    break;
    
                printf("%c ", Guesses[i][j]);
            }
            putchar('\n');
        }
    }

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    3 x 26 is small enough to not care about the cells you don't use.

    Sure, there are ways to do it involving dynamic allocation, but that's a large change in complexity.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    sorry i meant i wanted to put the created strings into an array but as i dont know how many strings can be created i cant create an array unless i do 26 cubed (17576)

  5. #5
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    would it be easier to just count the number of elements in each row and multiply them together ie 8 * 2 * 5 in this case and then declare the array

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    It's still only 70KB of memory.

    Yes it's a lot, if you're back in the 1980's on DOS, or programming a PIC micro.

    But if you're on any Windows or Linux from the last 20 years, it's a blip.


    > would it be easier to just count the number of elements in each row and multiply them together ie 8 * 2 * 5 in this case and then declare the array
    Sure, you can allocate just that much as a linear array.
    Then do your own subscripting to make it look like a ragged array.

    But again - you're complicating the code before you know you need to complicate the code.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Well... just a tip unrelated: This is WRONG:
    Code:
    for ( int j = 0, i = 0; text[i]; i++, j = (j + 1) % plen )
      encrypted[i] = text[i] ^ pword[j];
    encrypted[len] = '\0';
    What will happen if text AND pword have "hel" string?

  8. #8
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    it passes fine however you get one hell of a lot of possible passwords

    i = 0 j = 0 text i = h pword = h
    i = 1 j = 1 text i = e pword = e
    i = 2 j = 2 text i = l pword = l
    i = 3 loop breaks as i = \0

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    It's just the encrypted[len] = '\0' that's "wrong" in the sense that it's pointless since 'encrypted' can contain '\0's within it, i.e., it is no longer a C-style string (since they cannot contain embedded '\0's). All that means is that you cannot treat it as a string, e.g., you cannot use strlen on it to determine it's length. That's not a problem, though. It's just something to keep in mind.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  10. #10
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    instead of len could i use size of text

  11. #11
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    You can use strlen on text since it's a proper 0-terminated string.
    Once you've done that you also know the length of encrypted since it will be the same.
    sizeof is not a way of determining a string's length in general since a string is the "active" data within a char array, which is not generally the full size of the array. sizeof gives the size in bytes (technically chars, which are usually bytes) of the object.

    Anyway, there is no problem. Just don't bother 0-terminating encrypted since it's pointless.

    Still, I doubt that your strategy is going to solve the problem, although I'm not sure I fully understand what you are trying to do. As I mentioned before, the question seems to be suggesting that you simply cycle through all possible passwords, decrypt the text, and see if it contains common words like "the". I was able to solve it just by looking for "the" appearing as a word at least 5 times. Just looking for passwords that yield only printable characters yields a few hundred results, all but one of which being gibberish.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  12. #12
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    i have whittled the list down from 17576 possible combinations down to 80 i was then going to test the groupings of three against the encrypted string but obviously that didn't work as each letter already worked in its allotted place so now its a case of trying all 80 against common words.

    However so i don't get false positives (i don't in this example as the doesn't fall in the same place twice when compared to the password) i need to eliminate some of the 80 which was why i was trying to do it dynamically.

  13. #13
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    this is what i was banging on about
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int myfunc( char *, int, int , int , int );
    void PrintGuesses( int [][26], int );
    int Countelements( int [][26], int );
    void GetPossPword( char [][4], int [][26] );
    
    int main()
    {
        char text[] = "The quick brown fox jumps, over the lazy dog!";
        char pword[] = "hel";
        char encrypted[sizeof text];
    
        int len = strlen( text );
        int plen = strlen( pword );
    
        for ( int j = 0, i = 0; text[i]; i++, j = (j + 1) % plen )
            encrypted[i] = text[i] ^ pword[j];
        encrypted[len] = '\0';
    
        int Guesses[ sizeof pword - 1 ][26] = { 0 };
        // Don't use numbers for letters, e.g., say 'A' instead of 65.
        for ( int StartIndex = 0; StartIndex < plen; StartIndex++ )
        {
            int GuessIndex = 0;
    
            for ( int i = 'a'; i <= 'z'; i++ )
            {
                if ( myfunc( encrypted, i, StartIndex, len, plen ) )
                {
                    Guesses[StartIndex][GuessIndex] = i;
                    GuessIndex++;
                }
            }
            //putchar('\n');
        }
    
        PrintGuesses( Guesses, plen );
    
        char PossPwords[Countelements( Guesses, plen )][sizeof pword];
    
        GetPossPword( PossPwords, Guesses );
        for ( int i = 0; i < Countelements( Guesses, plen ); i++ )
            printf("%d = %s\n", i, PossPwords[i]);
    
        char Decrypted[sizeof encrypted] = { '\0' };
    
        for ( int i = 0; i < Countelements( Guesses, plen ); i++ )
        {
            for ( int y = 0, x = 0; x < sizeof encrypted - 1; x++, y = (y + 1) % plen )
            {
                Decrypted[x] = encrypted[x] ^ PossPwords[i][y];
            }
            if ( ( strstr( Decrypted, "the") != NULL ) || ( strstr( Decrypted, "The") != NULL ))
                printf("%s\n", Decrypted);
        }
    
        return 0;
    }
    
    int myfunc( char *Encrypted, int i, int StartIndex, int len, int plen )
    {
        int Letter = 1;
    
        for ( int j = StartIndex; j < len; j += plen )
        {
            int x = Encrypted[j] ^ i;
            if ( ! ( ( x >= 'A' && x <= 'Z' ) || ( x >= 'a' && x <= 'z' ) || (  x >= ' ' && x <= '@' ) ) )
            {
                Letter = 0;
                break;
            }
        }
        return Letter;
    }
    
    void PrintGuesses( int Guesses[][26], int plen )
    {
        for ( int i = 0; i < plen; i++ )
        {
            printf("%d  ", i);
            for ( int j = 0; j < 26; j++ )
            {
                if ( Guesses[i][j] == 0 )
                    break;
    
                printf("%c ", Guesses[i][j]);
            }
            putchar('\n');
        }
    }
    
    void GetPossPword( char PossPword[][4], int Guesses[][26] )
    {
        for ( int x = 0, i = 0; Guesses[0][i] != 0; i++ ) //first letter
            for ( int j = 0; Guesses[1][j] != 0; j++ ) // second letter
                for ( int k = 0; Guesses[2][k] != 0; k++ ) //third letter
                {
                    PossPword[x][0] = Guesses[0][i];
                    PossPword[x][1] = Guesses[1][j];
                    PossPword[x][2] = Guesses[2][k];
                    PossPword[x][3] = '\0';
                    x++;
                }
    }
    
    int Countelements( int Guesses[][26], int x )
    {
        int Counter = 1;
    
        for ( int y = 0, i = 0; i < x; i++, y = 0 )
        {
            for ( int j = 0; Guesses[i][j] != 0; j++ )
                y++;
    
            Counter *= y;
        }
    
        return Counter;
    }

  14. #14
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    here is the working article
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define INPUTFILE "cipher.txt"
    
    int get_text(char *text) {
        FILE *file = fopen(INPUTFILE, "r");
        if (!file) {
            perror(INPUTFILE);
            exit(EXIT_FAILURE);
        }
    
        int len = 0;
        // The %*c reads and ignores the comma after the integer.
        for (int ch; fscanf( file, "%d%*c", &ch ) == 1; )
            text[len++] = ch;
        fclose(file);
    
        return len;
    }
    
    int IsPrintable( int x )
    {
        return ( x > 32 && x < 127 )  == 1;
    }
    
    int LetterGuess( char *Encrypted, int i, int StartIndex, int len, int plen )
    {
        int Letter = 1;
    
        for ( int j = StartIndex; j < len; j += plen )
        {
            int x = Encrypted[j] ^ i;
            //if ( ! ( ( x >= 'A' && x <= 'Z' ) || ( x >= 'a' && x <= 'z' ) || (  x >= ' ' && x <= '@' ) || ( x >= 9 && x <= 13 ) ) )
            if ( !( x >= 1 && x <= 126 ))
            {
                Letter = 0;
                break;
            }
        }
        return Letter;
    }
    
    void PrintGuesses( int Guesses[][26], int plen )
    {
        for ( int i = 0; i < plen; i++ )
        {
            printf("%d  ", i);
            for ( int j = 0; j < 26; j++ )
            {
                if ( Guesses[i][j] == 0 )
                    break;
    
                printf("%c ", Guesses[i][j]);
            }
            putchar('\n');
        }
    }
    
    void GetPossPword( char PossPword[][4], int Guesses[][26] )
    {
        for ( int x = 0, i = 0; Guesses[0][i] != 0; i++ ) //first letter
            for ( int j = 0; Guesses[1][j] != 0; j++ ) // second letter
                for ( int k = 0; Guesses[2][k] != 0; k++ ) //third letter
                {
                    PossPword[x][0] = Guesses[0][i];
                    PossPword[x][1] = Guesses[1][j];
                    PossPword[x][2] = Guesses[2][k];
                    PossPword[x][3] = '\0';
                    x++;
                }
    }
    
    int Countelements( int Guesses[][26], int x )
    {
        int Counter = 1;
    
        for ( int y = 0, i = 0; i < x; i++, y = 0 )
        {
            for ( int j = 0; Guesses[i][j] != 0; j++ )
                y++;
    
            Counter *= y;
        }
    
        return Counter;
    }
    
    int main()
    {
        char text[1500]; // Input has 1455 chars
        char Pword[] = "aaa";
        int len = get_text(text);
        int plen = strlen(Pword);
    
        //printf("%d\n", len); // should print 1455
    
        // Encrypted characters are not necessarily printable.
        for ( int i = 0; i < len; i++)
            printf(IsPrintable(text[i]) ? "%c" : "{0x%02X}", text[i]);
        putchar('\n');
    
        int Guesses[ sizeof Pword - 1 ][26] = { 0 };
        // Don't use numbers for letters, e.g., say 'A' instead of 65.
        for ( int StartIndex = 0; StartIndex < plen; StartIndex++ )
        {
            int GuessIndex = 0;
    
            for ( int i = 'a'; i <= 'z'; i++ )
            {
                if ( LetterGuess( text, i, StartIndex, len, plen ) )
                {
                    Guesses[StartIndex][GuessIndex] = i;
                    GuessIndex++;
                }
            }
            //putchar('\n');
        }
    
        PrintGuesses( Guesses, plen );
    
        char PossPwords[Countelements( Guesses, plen )][sizeof Pword];
    
        GetPossPword( PossPwords, Guesses );
        for ( int i = 0; i < Countelements( Guesses, plen ); i++ )
            printf("%d = %s\n", i, PossPwords[i]);
    
        char Decrypted[sizeof text] = { '\0' };
    
        for ( int i = 0; i < Countelements( Guesses, plen ); i++ )
        {
            for ( int y = 0, x = 0; x < len; x++, y = (y + 1) % plen )
            {
                Decrypted[x] = text[x] ^ PossPwords[i][y];
            }
            if ( ( strstr( Decrypted, "the") != NULL ) || ( strstr( Decrypted, "The") != NULL ))
                if ( ( strstr( Decrypted, "From") != NULL ) || ( strstr( Decrypted, "from") != NULL ))
                printf("%s\n", Decrypted);
        }
        return 0;
    }

  15. #15
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Good job! Here's mine if you're interested.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
     
    #define INPUTFILE "cipher.txt"
    #define MAXWORD   3  // length of word "the"
    #define PWORDLEN  3
     
    int get_text(char *text) {
        FILE *file = fopen(INPUTFILE, "r");
        if (!file) { perror(INPUTFILE); exit(EXIT_FAILURE); }
        int len = 0;
        for (int ch; fscanf(file, "%d%*c", &ch) == 1; ) text[len++] = ch;
        fclose(file);
        return len;
    }
     
    int decrypt(const char *text, int len, const char *pword, char *out) {
        while (len--) {
            *out++ = *text++ ^ *pword++;
            if (!isprint( out[-1]) && !isspace(out[-1])) return 0;
            if (!*pword) pword -= PWORDLEN;
        }
        *out = 0;
        return 1;
    }
     
    // Return words <= MAXWORD in length, converted to lowercase.
    // A word is all letters with a non-letter before and after it.
    const char *next_word(const char *pos, char *word) {
        while (1) {
            while (*pos && !isalpha(*pos)) ++pos;
            if (!*pos) break;
            const char *end = pos;
            while (isalpha(*end)) ++end;
            if (end - pos <= MAXWORD) {
                for ( const char *p = pos; p < end; ++p )
                    word[p - pos] = tolower( *p );
                word[end - pos] = 0;
                return end;
            }
            pos = end;
        }
        return NULL;
    }
     
    int count_thes(const char *text) {
        int cnt = 0;
        char word[MAXWORD + 1];
        const char *pos = text;
        while ((pos = next_word(pos, word)))
            cnt += strcmp(word, "the") == 0;
        return cnt;
    }
     
    int main() {
        char text[1500]; // Input has 1455 chars
        int len = get_text(text);
        for (char a = 'a'; a <= 'z'; ++a)
        for (char b = 'a'; b <= 'z'; ++b)
        for (char c = 'a'; c <= 'z'; ++c) {
            char out[1500], pword[PWORDLEN + 1] = { a, b, c };
            if (decrypt(text, len, pword, out) && count_thes(out) >= 5) {
                printf("%s\n", pword);
                printf("%s\n", out);
            }
        }
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Declare 2D array without size, give size later
    By ColeBacha in forum C Programming
    Replies: 4
    Last Post: 04-18-2019, 11:50 PM
  2. Best way to declare an array size
    By pepito8 in forum C Programming
    Replies: 7
    Last Post: 01-21-2018, 02:32 PM
  3. unknown size array
    By archriku in forum C Programming
    Replies: 14
    Last Post: 05-07-2009, 11:29 PM
  4. How To Declare and Dynamically Size a Global 2D Array?
    By groberts1980 in forum C Programming
    Replies: 26
    Last Post: 11-15-2006, 09:07 AM
  5. array of unknown size
    By richdb in forum C Programming
    Replies: 7
    Last Post: 02-25-2006, 11:48 AM

Tags for this Thread