Thread: browsing through history commands

  1. #1
    Registered User
    Join Date
    Dec 2004
    Location
    The Netherlands
    Posts
    91

    browsing through history commands

    Hi everyone,

    I want to implent dos like arrow keys for browsing between the previously typed text. What is a good way of doing this, I was thinking of storing them in pointers,
    Code:
    char *p[16];
    and when counter is > 16, free and re-allocate 0, and start there again. This should keep 17 commands in memory.

    Are there any good algorithms for this? Or can someone show an example of how this could be done?

    Best regards.

    • OS: MS Windows XP
      Compiler: MS VC++ 6.0

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    for 17 commands you need array of 17 members, not 16

    And 2 indexes - last stored command and fisrt stored command that will be advanced in the cyclic manner.

    The rest that you described seems to be OK
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Keep an index counter. When the user types something, move it over to p[index]. Then increment index. If it goes beyond the limit, set index to 0. That way you have a circular array, and you're always pointing to the latest entry typed in.

  4. #4
    Registered User
    Join Date
    Dec 2004
    Location
    The Netherlands
    Posts
    91
    Thanks for the responses,

    I am a bit confused, can someone help me out;

    Code:
    int main(void) {
    	char *p[16];
    	int pindex = 0;
    
    	while(1) {
    		if(pindex > 15) {
    			pindex = 0;
    		}
    		p[pindex] = (char *)malloc(sizeof(char)*128);
    		fgets(p[pindex], 127, stdin);
    		//if(!strcmp(p[pindex], "break")) break;
    
    		if(pindex == 0) {
    			printf("There is no last item\n");
    		}
    		else {
    			printf("Last thing you typed: %s\n", p[pindex-1]);
    		}
    
    		pindex++;
    	}
    
    	for(pindex = 0;pindex < 16;pindex++) free(p[pindex]);
    
    	return 0;
    }
    How can I put the index to 15 when its a 'second-time' 0. (first time i initialize it to 0, second time it jumps to 0 when 16 is reached)

  5. #5
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    fgets is inclusive of the null terminator, so its,

    Code:
    fgets(p[pindex], 128, stdin);
    Also don't cast malloc see the FAQ.

    Not sure what you mean, but
    Code:
    if(pindex > 15) {
    pindex = 0;
    }
    Isn't inclusive of 15, so 16 is a valid index (in-fact its not, its out-of-bounds)

    Code:
    if(pindex >= 15)
        pindex = 0;
    You also don't check if malloc fails (it returns NULL if it fails).
    Last edited by zacs7; 05-22-2007 at 01:52 AM.

  6. #6
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    You have a memory leak if the user types more than 16 things. First of all, set every element of p to zero at the start. Then before you malloc(), check to see if p[pindex] is NULL. If it is, only then do you have to malloc().

    To adjust pindex back to 15 for the last element, I would recommend an extra variable to calculate the last index.

    Here's an altered version of your code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
    	char *p[16] = { NULL };
    	int pindex = 0, plast;
    	
    	while(1)
    	{
    		if(!p[pindex])
    		{
    			p[pindex] = (char *)malloc(sizeof(char)*128);
    			if(!p[pindex])
    			{
    				printf("Out of memory.\n");
    				break;
    			}
    		}
    		fgets(p[pindex], 128, stdin);
    		/* if(!strcmp(p[pindex], "break")) break; */
    		plast = (pindex == 0) ? (15) : (pindex - 1);
    		if((pindex == 0) && (!p[15]))
    		{
    			printf("There is no last item\n");
    		}
    		else
    		{
    			printf("Last thing you typed: &#37;s\n", p[plast]);
    		}
    		pindex = (pindex + 1) % 16;
    	}
    	for(pindex = 0;pindex < 16;pindex++)
    	{
    		free(p[pindex]);
    	}
    
    	return 0;
    }

  7. #7
    Registered User
    Join Date
    Dec 2004
    Location
    The Netherlands
    Posts
    91
    First of all, thanks again for the responses..

    Quote Originally Posted by zacs7 View Post
    Also don't cast malloc see the FAQ.
    Then, I get an error saying could not convert from void *, I guess its my compiler..

    Quote Originally Posted by MacGyver View Post
    Here's an altered version of your code:
    Thanks, I think I can sort it out from here, however, I do not understand this part,
    Code:
    pindex = (pindex + 1) % 16;
    what is the purpose of this?

  8. #8
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Quote Originally Posted by apsync View Post
    Then, I get an error saying could not convert from void *, I guess its my compiler..
    Remember to include stdlib.h. If that doesn't fix it, you might be compiling this as a C++ program. C++ doesn't allow implicit casts from void *. C does.

    Quote Originally Posted by apsync View Post
    Thanks, I think I can sort it out from here, however, I do not understand this part,
    Code:
    pindex = (pindex + 1) % 16;
    what is the purpose of this?
    pindex will be raised by one, and then integer divided by 16 and the remainder will be assigned to pindex.

    If pindex is 0, pindex + 1 is 1, and then integer divided by 16 is 0, with a remainder of 1. Hence pindex is just raised to one.

    The trick is for when pindex is 15. pindex + 1 would be 16. 16 / 16 is 1, with a remainder of 0.

    That's how you can get pindex to loop back to 0.

  9. #9
    Registered User
    Join Date
    Dec 2004
    Location
    The Netherlands
    Posts
    91
    Ah, thank you everything is clear now..
    Quote Originally Posted by MacGyver View Post
    Remember to include stdlib.h.
    My bad, forgot to include that header.

  10. #10
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    to avoid checking null pointer on every iteration of the loop - you can allocate memory for all 16 strings before loop, check that all pointers are not null and then - run the loop already without check of the null-pointer...

    And free the memory after the work is done - as you do now...
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Executing DOS commands from inside an image
    By Moony in forum C Programming
    Replies: 6
    Last Post: 03-16-2008, 12:40 PM
  2. Replies: 2
    Last Post: 07-27-2007, 12:48 PM
  3. Browsing through history in Editbox
    By apsync in forum Windows Programming
    Replies: 12
    Last Post: 05-25-2007, 09:05 AM
  4. Disable ALT key commands
    By Lionmane in forum Windows Programming
    Replies: 9
    Last Post: 09-23-2005, 10:41 AM
  5. best way to search through 'history'
    By anykey in forum C++ Programming
    Replies: 2
    Last Post: 08-16-2005, 04:31 PM