Click here to Skip to main content
15,889,992 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi again .. and thank you for your last answer to my question with the size of an array. Now I want to show you what I want to do with this array, but seems I still don't get it why I can't assign the size of the array

Here the size is known and is very easy to work with:

C++
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

#define END_SELECTED 6 // last highlighted choise selected
#define ARRAYSIZE(sel)	(sizeof(sel) / sizeof(sel[0]))
#define KEY_UP		72
#define KEY_DOWN	80
#define KEY_ENTER	13

void hideCursor();
void changeUser();
void SelChangeUser(unsigned int select);
void newUser();
void oldUser();
void selOldUser(unsigned int select);
void deleteUser();

main()
{
	hideCursor();
	changeUser();
	
	return (0);
}

void hideCursor()
{
	HANDLE cursorHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = FALSE;
    SetConsoleCursorInfo(cursorHandle, &info);
}

void changeUser()
{
	static int select = 0;
	int x;
	
	SelChangeUser(select);
	
	while((x = _getch()))
	{
		switch(x)
		{
		case KEY_UP:
			{
				select -= 2;
				if(select < 0)
					select = 0;
				SelChangeUser(select);
			}break;
			
		case KEY_DOWN:
			{
				select += 2;
				if(select > END_SELECTED)
					select = END_SELECTED;
				SelChangeUser(select);
			}break;
			
		case KEY_ENTER:
			{
				switch(select)
				{
				case 0:
					{
						newUser();
						SelChangeUser(select);
					}break;
					
				case 2:
					{
						oldUser();
						SelChangeUser(select);
					}break;
					
				case 4:
					{
						deleteUser();
						SelChangeUser(select);
					}break;
					
				case 6:
					{
                        printf("\n\n\n\n\t\t\t\tExit Program");
                        exit(0);
					}break;
				}
			}break;
		}
	}
}

void SelChangeUser(unsigned int line)
{
	char *selector[] = // array of pointers initialized 
    {
        "\t  New user",
        "\t  New user",
        "\t  Old user",
        "\t  Old user",
		"\tDelete  user",
		"\tDelete  user",
        "\t    Exit",
        "\t    Exit"
    };
	
	unsigned int i;
	
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
	system("cls");
    printf("\n\t\t\t\tInteractive Menu\n");
    printf("\t\t\t\t-------------\n\n\n");
    printf("\tChoose an option:\n\n\n\n\n");
	
	for(i = 0; i < ARRAYSIZE(selector); i += 2)
    {
        if(i == select)
        {
            //if selected change color to Green
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
			printf("%s\n\n", selector[i]);
        }
        else
        {
            // otherwise white color
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
			printf("%s\n\n", selector[i + 1]);
        }
    }
}

void newUser()
{...
}

void oldUser()
{...
}

void deleteUser()
{...
}


Okay, now when program runs if I select old user I will access a file text called oldUser.txt where name of users will be saved like this:


oldUser.txt
Alex
Alex
Frank
Frank
Gabriel
Gabriel


because I want my array of pointers to be exactly like this:

C++
char *selector[] =
    {
        "\t  New user",
        "\t  New user",
        "\t  Old user",
        "\t  Old user",
		"\tDelete  user",
		"\tDelete  user",
        "\t    Exit",
        "\t    Exit"
    };


Now oldUser() and selOldUser() functions look like this:

C++
void oldUser()
{
    int last_selected = 0;

    FILE *file = fopen("newUser.txt", "r");
    FILE *file2 = fopen("oldUser.txt", "a+");
    char buf[MAX] = {};

    for(int i = 0; fgets(buf, sizeof buf, file) != NULL; i++)
    {
        fprintf(file2, "%s", buf);
        fprintf(file2, "%s", buf);
    }

    fclose(file);
    rewind(file2);

    for(last_selected = 0; fgets(buf, sizeof buf, file2) != NULL; ++last_selected);

    fclose(file2);
    remove("oldUser.txt");

    static int select = 0;
    unsigned int x;

    selOldUser(select);

    while((x = _getch()))
    {
        switch(x)
        {
        case KEY_UP: // If Key up from Keyboard is pressed
            {
                select -= 2;
                if(select < 0)
                    select = 0;
                selOldUser(select);
            }break;

        case KEY_DOWN: // If Key down from Keyboard is pressed
            {
                select += 2;
                if(select > (last_selected - 2))
                    select = (last_selected - 2);
                selOldUser(select);
            }break;

        case KEY_ENTER: // If Key Enter from Keyboard is pressed
            {
                // I'll do something here.
            }break;
        }
    }
}

selOldUser(unsigned int select)
{
    FILE *file = fopen("newUser.txt", "r"); // where new user are stored
    FILE *file2 = fopen("oldUser.txt", "a+");
    char buffer[256] = {};
    char buf[80] = {};
    int enteries = 0;
    int k = 0;

    for(k = 0; fgets(buffer, sizeof buffer, file) != NULL; k++)
    {
        fprintf(file2, "%s", buffer);
        k++
        fprintf(file2, "%s", buffer);
    }

    fclose(file);
    rewind(file2);

    char *selector[k]; /* here I cannot set the size to k. Doesn't work.
                          How to make the size equal to number of lines
                          I retrieve from the for loop ???
                       */

    while(enteries < k && fgets(buf, sizeof buf, file2) != NULL)
    {
        selector[enteries] = malloc(strlen(buf) + 1);
        strcpy(selector[enteries], buf);
        ++enteries;
    }

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
    system("cls");
    printf("\n\t\t\t\tNew type menu\n");
    printf("\t\t\t\t-------------\n\n\n");
    printf("\tSelect user:\n\n\n\n\n");

    unsigned int i;

    for(i = 0; i < ARRAYSIZE(selector); i += 2)
    {
        if(i == select)
        {
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
            printf("\t%s\n\n", selector[i]); // element is even
        }
        else
        {
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
            printf("\t%s\n\n", selector[i + 1]); // element is odd
        }
    }

    free(*selector);
    fclose(file2);
    remove("oldUser.txt");
}


What I have tried:

I just assign k to size of the array, but this can't be done.
Posted
Updated 22-Mar-21 0:32am
v2
Comments
M@gelearn 22-Mar-21 6:15am    
The code works only if I assign its size from the beginning like this for eg.

#define LINE 20

and my array will be
char *selector[LINE];

1 solution

Don't store "display format" text in your data, store just the bas information. You cann add the tabs and spaces when you display it.

As to the rest, if you do not know how big your array will be, then the best way of managing it is to use malloc and realloc as you process your data. Start with a reasonable number of entries (e.g. 10) and whenever you need more space double the size and use realloc to get the expanded array.

[edit]
You can populate a dynamic array of names from a file with the following code:
C++
#define MAX 32

int main()
{
    char** usernames; // an array of pointers
    int number = 10;  // the initial number
    usernames = (char**)malloc(sizeof(char*) * number); // allocate space for 10 pointers
    int i = 0;
    FILE *file = fopen("test.txt", "r");
    do
    {
        usernames[i] = (char*)malloc(MAX); // allocate space in the next slot
        usernames[i][0] = '\0';
        char* pNext = fgets(usernames[i], MAX, file); // read into next buffer
        if (pNext == NULL)
            break;  // end of file entries
        i++;
        if (i == number) // if we have used all slote
        {
            number += 10; // add 10 more entries
            usernames = (char**)realloc(usernames, sizeof(char*) * number);
        }
    } while (1); // keep going until end of input file
    usernames[i] = NULL; // mark the end of the entries
    fclose(file);

    // now print all the entries
    for(i = 0; i < number && usernames[i] != NULL; i++)
    {
        printf("%d: %s", i, usernames[i]);
    }

    return 0;
}


You can adapt the above code to suit your own requirements.
[/edit]
 
Share this answer
 
v2
Comments
M@gelearn 22-Mar-21 9:09am    
Ohh sorry McCutchan, but I still don't understand how to do this, I did cast malloc in a while loop here:

while(enteries < k && fgets(buf, sizeof buf, file2) != NULL)
{
selector[enteries] = malloc(strlen(buf) + 1);
strcpy(selector[enteries], buf);
++enteries;
}

still doesn't work.. :\
Richard MacCutchan 22-Mar-21 11:15am    
See my update solution.
M@gelearn 22-Mar-21 12:04pm    
Ohh.. that's awesome.. :)
Thanks Richard.. I feel happy.. and 5s for your solution.
Well.. I'm too low in knowledge, soo this was a great lesson for me, and doesn't mean I solve the problem.. more will come. I fell however sad in the end, cose in almost a year of reading and doing small programs I wasn't able to solve this one. Maybe just because I didn't have a teacher, I just do this on my own cose I like it. I wish I could give you another 5 stars , cose you deserve it.
Thanks again and my apologies for bother with these things, but for me means so much.
Cheers !!!
Richard MacCutchan 22-Mar-21 12:06pm    
Thank you. If you are teaching yourself then some of these concepts are not easy, even though C is a fairly simple language.
M@gelearn 22-Mar-21 12:09pm    
Just one more thing to add, just because I did not see it in your code, this doesn't mean you didn't know it and I'm sure you forgot to free the memory at the end.
I just did this before the function ended free(usernames);

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900