Thread: Improving the efficiency..

  1. #1
    Registered User
    Join Date
    Sep 2008
    Posts
    5

    Improving the efficiency..

    Hey all, recently I've played around with pointers and some win32 API and I've came up with this portion of code, to basically load a set of string from a file on a secondary storage, store it in the memory and then print it on the screen. The apparent problem is that this code draws slowly comparatively with printf function. I don't want to use printf because i am limited to the coordinates (0,0) only. I want to be able to print anywhere on the screen preserving the format of my string. So basically this function is able to do it but doing it slowly. This happen only if the string happens to be large, like maybe 4kb? So I am wondering is there anyway that i can optimize it? I am suspecting that the problem comes from the while loop that I used to individually scan the string for any escape character inorder to process new line therefore to preserve the user-defined coordinates. (My function printSTR allows the user to print the string on a specific location of a screen instead of printf which only prints from (0,0). )



    Code:
    //////////////////////////////////////////////////////////////////////////////
    // void printSTR(char *text, int x, int y)
    // Author:   -aaronljx-
    // 
    // To print a string to the console screen from a file preferably, you need
    // to call the function LoadSTR first before printing it.
    //
    // Usage:
    // char *text    -> pointer to the address of the string
    // int x, int y  -> coordinates of where the string to be printed
    //
    // eg.
    // printSTR("This is to print directly", 2, 5);
    //
    // char *pStr1;
    // pStr1 = LoadSTR("file1.txt");
    // printSTR( pStr1, 2, 5 );
    // free(pStr1);
    //
    // Note: Make sure you free every string loaded from file with
    // the free function, free(var_name);
    //////////////////////////////////////////////////////////////////////////////
    void printSTR(char *text, int x, int y)
    {
    	gotoXY(x, y);
    
    	while ( *text )
    	{
    		if ( *text == 10 ) // if *text returns \n
    		{
    			y++;
    			gotoXY(x, y);
    			text++;
    		}
    		else
    		{
    			printf("%c", *text);
    			text++;
    		}
    	}
    
    	return;
    }
    
    //////////////////////////////////////////////////////////////////////////////
    // char *LoadSTR(char *filename)
    // Author:   -aaronljx-
    //
    // This function works hand in hand with the function printSTR
    // to load string directly from file and print it on the screen
    // on the given coordinates.
    //
    // Usage:
    // char *filename  -> the location of the string in your secondary storage
    //
    // Returns:
    //   -> the address of the loaded string
    // eg.
    // char *pStr1;
    // pStr1 = LoadSTR("file name.txt");
    // printSTR( pStr1, 2, 5 );
    // free(pStr1);
    //
    // Note: Each time you load a string from file, make sure you free it
    // after using it. This is important.
    //////////////////////////////////////////////////////////////////////////////
    char *LoadSTR(char *filename)
    {
    	FILE *buffer;
    	char *pString, temp;
    	int nChar = 0;
    
    	if ( !( buffer = fopen( filename, "r" ) ) )
    	{
    		printf("\aError! Unable to open required files.\n");
    		getchar();
    		exit(EXIT_FAILURE);
    	}
    
    	while ( fscanf( buffer, "%c", &temp ) != EOF )
    		nChar++;
    
    	pString = (char*) calloc( nChar + 1, sizeof(char) );
    
    	rewind(buffer);
    	fscanf( buffer, "%[^\0]", pString );
    	fclose(buffer);
    
    	return pString;
    }

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Small improvement would be to use putc() or putchar() instead of printf() - since you are printing a char at a time, it seems unnecessary to use printf which is quite complex.
    A bigger improvement would be to printf() large chunks of the string (using something like strchr() to find the newlines).

    You can certainly do the same thing in the read, using fgetc() instead of the more complex scanf() function. Reading the same string twice (first scanning, then reading the whole string) seems unnecessarily complicated. Use a scheme where you pre-allocate a small buffer, and grow it using realloc instead. [Or, if you insist on counting the letters first, use fread to read the entire string at once].

    Code:
    		if ( *text == 10 ) // if *text returns \n
    		{
    			y++;
    			gotoXY(x, y);
    			text++;
    would it not be clearer to use '\n' instead of 10 - not to mention that it would be portable to a system where 10 is not the quivalent of '\n'. [No, I don't know of any such system - but I wouldn't be surprised if they exist].

    Second, isn't x supposed to change to 0 as well for a newline?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    This is a very poor and slow way of determining the length of a file:
    Code:
    	while ( fscanf( buffer, "%c", &temp ) != EOF )
    		nChar++;
    Regarding:
    Code:
    	pString = (char*) calloc( nChar + 1, sizeof(char) );
    You don't need a zero-filled piece of memory since you're reading data over top of the block immediately afterwards. An uninitialised piece of memory will be fine, and slightly faster. Just use malloc not calloc, and only put the single required '\0' on the end.
    Secondly, don't cast the result of malloc/calloc.

    Lastly, parse the string before printing and change all the '\n' characters to '\0' characters and make one call to printf for each line.
    Last edited by iMalc; 11-29-2008 at 02:46 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  4. #4
    Registered User
    Join Date
    Sep 2008
    Posts
    5
    Quote Originally Posted by matsp View Post
    Small improvement would be to use putc() or putchar() instead of printf() - since you are printing a char at a time, it seems unnecessary to use printf which is quite complex.
    A bigger improvement would be to printf() large chunks of the string (using something like strchr() to find the newlines).

    You can certainly do the same thing in the read, using fgetc() instead of the more complex scanf() function. Reading the same string twice (first scanning, then reading the whole string) seems unnecessarily complicated. Use a scheme where you pre-allocate a small buffer, and grow it using realloc instead. [Or, if you insist on counting the letters first, use fread to read the entire string at once].

    Code:
    		if ( *text == 10 ) // if *text returns \n
    		{
    			y++;
    			gotoXY(x, y);
    			text++;
    would it not be clearer to use '\n' instead of 10 - not to mention that it would be portable to a system where 10 is not the quivalent of '\n'. [No, I don't know of any such system - but I wouldn't be surprised if they exist].

    Second, isn't x supposed to change to 0 as well for a newline?

    --
    Mats
    Ahh thanks for the advice.. I also thought about writing my own code to format the string, I am thinking that probably after loading the big chunk of string into the memory, I'll create another buffer, calculate the whitespaces required if the user wants to print every line at the coordinate, (5,2) then insert the whitespace into the string and print the whole string as a block. Actually I thought if I use '\n', the compiler automatically changes it to the ASCII counterpart (which is 10) right?

    Btw if I use realloc instead, how do I grow it? I don't really know about that function actually. Besides I have also considere using WriteConsoleOutput function as an alternative solution by first creating another screen buffer, draw the whole block on it, then read in the contents to a CHAR_INFO array, then rewrite it on the standard output handle, finally destroy the temporary screen buffer. Any alternatives? Thanks.

  5. #5
    Registered User
    Join Date
    Sep 2008
    Posts
    5
    Quote Originally Posted by iMalc View Post
    This is a very poor and slow way of determining the length of a file:
    Code:
    	while ( fscanf( buffer, "%c", &temp ) != EOF )
    		nChar++;
    Then any alternative?

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    realloc() takes a size that it will resize to. Common variants is to take the current size and allocate twice as much - so : size = size * 2; whenever you reach the size.

    Or, you can figure out the actual size of the file by using fseek() with SEEK_END and 0 as the arguments, then use ftell() to get the current position, which is zero bytes back from the end of the file (in other words, at the end of the file). Just don't forget to set it back to the beginning with SEEK_BEG and 0 to get back to the start. [Note that this is not quite precise, since in text-files, '\n' is sometimes stored as "\r\n", so every newline takes up two positions]. But it will give you something that is AT LEAST big enough.

    And yes, '\n' will translate to whatever newline is on the machine you are compiling for - which is most often 10, but if it isn't, then it's much better that the compiler translates it than you translating it.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    You could try reading up on io.h

    http://www.digitalmars.com/rtl/io.html#_filelength

    See _filelength function

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by slingerland3g View Post
    You could try reading up on io.h

    http://www.digitalmars.com/rtl/io.html#_filelength

    See _filelength function
    Ehem, that is not a standard functiokn tho' (nor is io.h a standard header file, and I would not recommend using anything that even remotely relates to "digital mars").

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    True matsp. Though their are functions out there for this sort of thing. Listed below as well when googling around.

    http://www.warpspeed.com.au/cgi-bin/...PG4REF.INF+121

    States this is in the c Library reference.

  10. #10
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    [Off topic]

    Oh I have had no dealings or used code by them, but what is the deal with Digital Mars?

    [/Off topic]

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by slingerland3g View Post
    True matsp. Though their are functions out there for this sort of thing. Listed below as well when googling around.

    http://www.warpspeed.com.au/cgi-bin/...PG4REF.INF+121

    States this is in the c Library reference.
    Sure, but it also says
    Quote Originally Posted by WebPage
    This book describes the library functions provided by The IBM Developer's Toolkit for OS/2 Warp Version 4 (referred to in this book as The Developer' s Toolkit) product. Many of the functions are defined by the following language standards:
    (my bold - particularly notice the word "Many", which implies to me at least that some may not be).

    I wasn't trying to imply that such functions aren't available/possible. But it's not very difficult to make it with COMPLETELY STANDARD functions - depending on pre/post conditions (e.g do you need to store the current position of the file, or is setting it back to beginning fine) you may need about 3-4 lines of code.
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by slingerland3g View Post
    [Off topic]

    Oh I have had no dealings or used code by them, but what is the deal with Digital Mars?

    [/Off topic]
    It's a poorly written compiler that the author(s) charge money to use. Poor means compared to other offerings which are available for free, such as gcc and MS Visual Studio, both of which offer excellent compilers.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Efficiency with c++
    By pastitprogram in forum C++ Programming
    Replies: 17
    Last Post: 08-08-2008, 11:18 AM
  2. Efficiency of Reading a File
    By kiai_viper in forum C Programming
    Replies: 8
    Last Post: 07-23-2007, 08:55 AM
  3. Calculating space efficiency using sizeof()
    By markcls in forum C Programming
    Replies: 6
    Last Post: 05-19-2007, 05:25 AM
  4. Efficiency problems
    By Crazy Glue in forum C# Programming
    Replies: 15
    Last Post: 07-20-2006, 08:38 AM
  5. Binary tree search efficiency
    By ExCoder01 in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 10-23-2003, 10:11 PM