Advertisement

sccanf operation

Started by July 28, 2023 09:48 AM
3 comments, last by frob 1 year, 3 months ago

Hi Guys,

I presently have a program where I can load values from a file using fscanf() which is working fine.

	FILE *fp = fopen("level.h", "r");
		
	if (fp == NULL)
	{
		std::cout << "Error opening level.h\r\n";
		return;
	}

	int s, w;

	fscanf(fp, "%i", &numSect);
	for (s = 0; s < numSect; s++)
	{
		fscanf(fp, "%i", &S[s].ws);
		fscanf(fp, "%i", &S[s].we);
		fscanf(fp, "%i", &S[s].z1);
		fscanf(fp, "%i", &S[s].z2);
		fscanf(fp, "%i", &S[s].st);
		fscanf(fp, "%i", &S[s].ss);
	}

I am trying to now have a near identical function which can do the same thing but from a string (or even a char array), by using sscanf.

But for some reason, it always return the first value of the string (being “1”). It's not stepping through the rest of the numbers like fscanf does.

	std::string lvl = "1 0 4 0 40 1 4 4 192 288 256 288 0 1 1 0 256 288 256 352 0 1 1 90 256 352 192 352 0 1 1 0 192 352 192 288 0 1 1 90 288 48 30 0 0";

	sscanf(lvl.c_str(), "%d", &numSect);

	std::cout << "Sectors: " << numSect << "\r\n";

	for (int s = 0; s < numSect; s++)
	{
		sscanf(lvl.c_str(), "%d", &S[s].ws);	std::cout << "WS: " << S[s].ws << "\r\n";
		sscanf(lvl.c_str(), "%d", &S[s].we);	std::cout << "WE: " << S[s].we << "\r\n";
		sscanf(lvl.c_str(), "%d", &S[s].z1);	std::cout << "Z2: " << S[s].z1 << "\r\n";
		sscanf(lvl.c_str(), "%d", &S[s].z2);	std::cout << "Z2: " << S[s].z2 << "\r\n";
		sscanf(lvl.c_str(), "%d", &S[s].st);	std::cout << "ST: " << S[s].st << "\r\n";
		sscanf(lvl.c_str(), "%d", &S[s].ss);	std::cout << "SS: " << S[s].ss << "\r\n";
	}

Is there a parameter I am missing for sscanf() or something?

I have done a search on the internet and can't see where I am going wrong.

Any advice would be greatly appreciated.

With fscanf there is a file pointer that moves. With sscanf you don't have that. If you pass it the same string every time, you will get the same result every time. It's meant to be used to parse relatively short stings in one line of code. What you may want to use is a sting stream instead. Check out std::strstream. Also, if you are going to use a C++ I/O, you should probably update your file I/O to use streams also. As it stands you are mixing old C I/O with C++ I/O. It should work, but it just seems a bit clunky. But that's up to you.

Advertisement

Thanks for the reply there. It confirmed my suspicions.

I have written a work around which seems to do the job now.

A major detail I notice in your code and since we're not in the For Beginners forum, you're not checking the results of scanf().

Input functions can fail for many reasons. For the scanf() family the return value is the number of items successfully matched and processed, or EOF in the result of failure. The line fscanf(fp, "%i", &S[s].ws); is scanning for a single item, so it should be returning a count of 1 on success, but could also return 0 (it attempted to read but couldn't parse it as an integer) or return EOF. (EOF is typically defined as -1, but is implementation defined so always use the named constant EOF.)

This applies to the entire scanf() family, fscanf(), sscanf(), etc. Always check the return value because it can fail.

Whatever you're using as a replacement, be sure you're also checking for possible failure there, too. If you're using the c++ stream operators, errors will typically throw an exception and sets flags on the input stream. When programming, remember that failure is always an option.

This topic is closed to new replies.

Advertisement