Thread: Weird problem with sscanf

  1. #1
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476

    Weird problem with sscanf

    Hi, I've got a weird problem here:

    I have a routine of reading from a file and getting some values for the variables from it. Here's the problem:

    Code:
    ...
    	sscanf ( buffer,"%d : %d : %d : %d : %d",&mWidth, &mHeight, &mTransCol.transR, &mTransCol.transG , &mTransCol.transB);
    ...
    and the buffer's value (from debug) is:
    Code:
    buffer = "22 : 21 : 1 : 2 : 3\r\n\000..."
    the value of variables are:
    Code:
    mWidth=0 
    mHeight=21
    mTransCol.transR=1
    mTransCol.transG=2
    mTransCol.transB=3
    I'm confused. Why does the mWidth is 0 whereas in the buffer string it's clearly 22 ?? Can anybody help me with this?

  2. #2
    Registered User SKeane's Avatar
    Join Date
    Sep 2006
    Location
    England
    Posts
    234
    What type is mWidth, how are you printing the results? What is sscanf returning?

  3. #3
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by SKeane
    What type is mWidth, how are you printing the results? What is sscanf returning?
    mWidth is an int. And when I cout-ed the buffer, it displays the same as the value of buffer. And sscanf returned 5 (so I guess all the variables are successfully read).

  4. #4
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    BTW, before the troublesome line, there's a sequence of reading with fgets and sscanf. And the pervious sequence worked fine.

    Code:
            int scanBuff;
    
    	fgets (buffer, 255, fp);
            //looping through comments (#)
    	while (buffer[0] == '#' || buffer[0] == '\r' || buffer[0] == '\0' || buffer[0] == '\n' || strlen(buffer) == 0)
    	{
    		fgets (buffer, 255, fp);
    	}
    
    	scanBuff = sscanf ( buffer, "%s : %s : %s : %s : %d", nametemp, dirName, filename, widthfile, &mNumFonts);
    	
    	fgets (buffer, 255, fp);
            //looping through comments (#)
    	while (buffer[0] == '#' || buffer[0] == '\r' || buffer[0] == '\0' || buffer[0] == '\n' || strlen(buffer) == 0)
    	{
    		fgets (buffer, 255, fp);
    	}
    	scanBuff = sscanf ( buffer, "%d : %d : %d : %d : %d : %d : %d : %d", &mIndexLargeA, &mIndexSmallA, &mIndex0, &mIndexKoma, &mIndexDot, &mIndexDot2, &mIndexEq, &mIndexEs);
    
    	fgets (buffer, 255, fp);
            //looping through comments (#)
    	while (buffer[0] == '#' || buffer[0] == '\r' || buffer[0] == '\0' || buffer[0] == '\n' || strlen(buffer) == 0)
    	{
    		fgets (buffer, 255, fp);
    	}
    	scanBuff=sscanf ( buffer,"%d : %d : %d : %d : %d",&mWidth, &mHeight, &mTransCol.transR, &mTransCol.transG , &mTransCol.transB);

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    How did you declare buffer?

    What is the value in scanBuff when it appears wrong?
    It should be the number of conversions AND assignments, which in this case would seem to be 5.

    Also, fgets() returns a status which you should check.

    > buffer[0] == '\r' || buffer[0] == '\0' || strlen(buffer) == 0
    Unless you're using fgets() to read a binary file (not a good idea), none of these will be true
    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.

  6. #6
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by Salem
    How did you declare buffer?

    What is the value in scanBuff when it appears wrong?
    It should be the number of conversions AND assignments, which in this case would seem to be 5.

    Also, fgets() returns a status which you should check.

    > buffer[0] == '\r' || buffer[0] == '\0' || strlen(buffer) == 0
    Unless you're using fgets() to read a binary file (not a good idea), none of these will be true
    buffer is:
    char buffer[255];

    In the wrong line, scanBuff read 5 (so I guess the problem is not in in sscanf).

    The status returned from fgets is never NULL (so I guess the fgets is not faulty either)

    And for the "buffer[0] == '\r' || buffer[0] == '\0' || strlen(buffer) == 0", it worked fine and my file is opened in text mode. It just check whether a linefeed is found or not.

    So, I'm curious what is the matter with this code?

    EDIT:
    I tried to add a bogus variable so now the faulty line is:
    Code:
    	scanBuff=sscanf ( buffer,"%d : %d : %d : %d : %d : %d",&bogusVar, &mWidth, &mHeight, &mTransCol.transR, &mTransCol.transG , &mTransCol.transB);
    And guess what, in didn't work. The scanBuff showed 5, the mWidth is still 0 and the bogusVar is undetermined. How weird is that?
    Last edited by g4j31a5; 10-03-2006 at 07:56 PM.

  7. #7
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    You know, I've solved the problem with a little bit of tinkering. I defined a local temporary variable and then used it in the sscanf. After that the I set mWidth equivalent the temporary variable like so:
    Code:
            int tempW;
    	scanBuff=sscanf ( buffer,"%d : %d : %d : %d : %d", &tempW, &mHeight, &mTransCol.transR, &mTransCol.transG , &mTransCol.transB);
    
    	mWidth= tempW;
    And it worked (At last!!!!!!). BTW, I forgot to mention that mWidth is a private member variable (as well as mHeight and mTransCol in that matter). But still, the cause of the problem isn't solved and I'm still curious. But I'm happy with that, for now.

  8. #8
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    Well, now that you got that solved... may I suggest using stringstreams or lexical_cast instead? This is C++, after all, and sprintf is a very C solution... those very acceptable.
    Sent from my iPadŽ

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Can you post a small and complete program which demonstrates the problem.

    Your answer doesn't solve anything, it sweeps it under the carpet for it to reappear later on.
    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.

  10. #10
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by SlyMaelstrom
    Well, now that you got that solved... may I suggest using stringstreams or lexical_cast instead? This is C++, after all, and sprintf is a very C solution... those very acceptable.
    Yeah, that's what I thought too. But alas, the code was already in C (my application is in the most part C++, but in a few exceptions still in C like this one). And I kind of lazy to rewrite in in C++ style :P

  11. #11
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by Salem
    Can you post a small and complete program which demonstrates the problem.

    Your answer doesn't solve anything, it sweeps it under the carpet for it to reappear later on.
    Well, this is not the complete program, just the faulty function:

    Code:
    int CFont::init(char *infoPath, char *infoFile)
    {
    	char buffer[255];
    	char *strState; 
    	char filename[255], filename2[255];
    	char dirName[255];
    	char nametemp[255];
    	char widthfile[255];
    
    	//int bogusVar;
    	FILE *fp; //buffer config file
    
    
    	//Path&filename config file
    	strcpy(filename,infoPath);
    	strcat(filename,"/");
    	strcat(filename,infoFile);
    
    	int scanBuff, tempW;
    	
    	//open config file
    	if((fp=fopen(filename, "r")) == NULL)
    	{
    		printf("ERROR opening file %s\n\n", filename);
    		return -1;
    	}
    
    	//Reading configuration
    	strState = fgets (buffer, 255, fp);
            //looping through comments (#)
    	while (buffer[0] == '#' || buffer[0] == '\r' || buffer[0] == '\0' || buffer[0] == '\n' || strlen(buffer) == 0)
    	{
    		strState = fgets (buffer, 255, fp);
    	}
    
    	scanBuff = sscanf ( buffer, "%s : %s : %s : %s : %d", nametemp, dirName, filename, widthfile, &mNumFonts);
    	
    	strState = fgets (buffer, 255, fp);
            //looping through comments (#)
    	while (buffer[0] == '#' || buffer[0] == '\r' || buffer[0] == '\0' || buffer[0] == '\n' || strlen(buffer) == 0)
    	{
    		strState = fgets (buffer, 255, fp);
    	}
    	scanBuff = sscanf ( buffer, "%d : %d : %d : %d : %d : %d : %d : %d", &mIndexLargeA, &mIndexSmallA, &mIndex0, &mIndexKoma, &mIndexDot, &mIndexDot2, &mIndexEq, &mIndexEs);
    
    	strState = fgets (buffer, 255, fp);
            //looping through comments (#)
    	while (buffer[0] == '#' || buffer[0] == '\r' || buffer[0] == '\0' || buffer[0] == '\n' || strlen(buffer) == 0)
    	{
    		strState = fgets (buffer, 255, fp);
    	}
    	scanBuff=sscanf ( buffer,"%d : %d : %d : %d : %d",&mWidth, &mHeight, &mTransCol.transR, &mTransCol.transG , &mTransCol.transB);
    
    	//mWidth= tempW;
          	fclose(fp);
    }
    The class itself:
    Code:
    class CFont  
    {
    public:
    	CPicFont* getPicFont(int no);
    	int getCharWidth(char nama);
    	string getName();
    	void draw(int xx, int yy, char huruf);
    	void createFont(char* folder, char* nama, SDL_Rect blit_Reg, char huruf);
    	CFont();
    	CFont(char *fontInfoPath, char *fontInfoFile, CSurface* screen);
    	int getHeight();
    	int getWidth();
    	virtual ~CFont();
    
    private:
    	CSurface* mScreen;
    	int init(char *infoPath, char *infoFile);
    	int mNumFonts;
    	string mNamaFont;
    	TransparentColor mTransCol;
    	int mWidth;
    	int mHeight;
    	lstFontName mFontName;
    	lstFontHandle mFontHandle;
    	int mIndexLargeA; 
    	int mIndexSmallA; 
    	int mIndex0; 
    	int mIndexKoma;
    	int mIndexDot; 
    	int mIndexDot2;
    	int mIndexEq; 
    	int mIndexEs; 
    };
    The init function is called under the constructor.

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > just the faulty function:
    Doesn't help much - where it crashes does not necessary mean that's where the problem is.

    It's only possible to find such things with complete programs, I can't find such problems from random snippets.

    IE, I want to be able to do copy / paste / compile / run / examine crash without having to guess at what you missed out or provide my own wrappers around your snippets just to make it work.

    Given that it crashes in the ctor / init(), then (with a copy of the code) snip out every other member function and every other unused member variable and see if the problem persists. Your main() should just have a single CFont and then construct it.

    If that fails in the way you describe, then you can post the whole lot and we have something to go at.
    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.

  13. #13
    Its hard... But im here swgh's Avatar
    Join Date
    Apr 2005
    Location
    England
    Posts
    1,688
    On a side note, it is not usually a good idea to mix C and C++ code. Either do it one way or the other

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > &mTransCol.transR, &mTransCol.transG , &mTransCol.transB
    What types are these - unsigned char perhaps?
    Because if they are, that would easily explain why your values are being trashed, because sscanf is trying to write a whole int into that byte.

    A heavy dose of
    gcc -W -Wall prog.c
    would tell you when you mess up with sscanf conversions.

    Another reason for going solely with C++, the >> operator is type-safe in a way which sscanf can never be.
    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.

  15. #15
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by Salem
    > just the faulty function:
    Doesn't help much - where it crashes does not necessary mean that's where the problem is.

    It's only possible to find such things with complete programs, I can't find such problems from random snippets.

    IE, I want to be able to do copy / paste / compile / run / examine crash without having to guess at what you missed out or provide my own wrappers around your snippets just to make it work.

    Given that it crashes in the ctor / init(), then (with a copy of the code) snip out every other member function and every other unused member variable and see if the problem persists. Your main() should just have a single CFont and then construct it.

    If that fails in the way you describe, then you can post the whole lot and we have something to go at.
    Ah, ok I'll try that.

    > &mTransCol.transR, &mTransCol.transG , &mTransCol.transB
    What types are these - unsigned char perhaps?
    Because if they are, that would easily explain why your values are being trashed, because sscanf is trying to write a whole int into that byte.

    A heavy dose of
    gcc -W -Wall prog.c
    would tell you when you mess up with sscanf conversions.

    Another reason for going solely with C++, the >> operator is type-safe in a way which sscanf can never be.
    mTransCol are a struct with three unsigned integer values for the RGB values of the transparent color.

    Yeah, I was thinking about going full C++, but how can I read from the text between a token of ' : ' with >> operator? I know that the STL string's standard tokenizer is not so good.
    Last edited by g4j31a5; 10-04-2006 at 09:32 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Weird problem on '02 3.4L V6 auto
    By VirtualAce in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 01-12-2006, 12:05 AM
  2. Really Weird itoa Problem
    By Grantyt3 in forum C++ Programming
    Replies: 8
    Last Post: 12-20-2005, 12:44 AM
  3. very weird problem (pointers I think)
    By hannibar in forum C Programming
    Replies: 2
    Last Post: 10-11-2005, 06:45 AM
  4. Replies: 6
    Last Post: 05-12-2005, 03:39 AM
  5. Weird class problem!
    By aker_y3k in forum C++ Programming
    Replies: 2
    Last Post: 09-25-2002, 06:12 AM