Advertisement

Printing % to a string? I need MANY % to get the percent symbol

Started by April 15, 2018 04:02 PM
23 comments, last by diligentcircle 6 years, 10 months ago

Hi!

Depending on how the char array is passed I need to add many many % signs to actually get an % in the final place it is used. For example here i need 16 (!) signs since every pass it converts half of them each time it is passed (i got lots of nested functions that use an char array). 

Any way around this? It's kind of annoying to need to figure out how many % is "the right amount" for any given situation.


sprintf(tempText,  "Risk of hostilities: %d %%%%%%%%%%%%%%%%", www.ambushRisk[mood][0]);

 

Use a different character or split it out into two separate operations:


char buf[1000];
int i = 123;

// TODO: error checking, bounds checking, safe-versions of string functions
char* ptr = buf;
ptr += sprintf(ptr, "Text format, i=%d", i);
strcpy(ptr, " and five (5) percent signs: %%%%%");
	
cout << buf << endl;

https://ideone.com/fX8yfV

Advertisement

Collect all the values as a list of strings or so, and at the end, concatenate it to a single string.

Alternatively, insert already existing text as "%s" into the next string, so the "%" signs in it are not interpreted.

 

2 hours ago, suliman said:

sprintf(tempText, "Risk of hostilities: %d %%%%%%%%%%%%%%%%", www.ambushRisk[mood][0]);

Also since this topic was tagged C++, stringstream should be your prefered friend (and will also expose less security risks). So by doing something like this, you'll end up with the same thing that what you want to do, and in a more elegant fashion:


	std::stringstream ss;
	ss << "Risk of hostilities: " << www.ambushRisk[mod][0] << " %";
	// use it:
	std::cout << ss.str() << std::endl;
	

Is there any particular reason you're formatting a string several times? It seems to me this is something you should be avoiding.

If you're appending something, you should format only the appended portion, e.g.:

sprintf(newstr, "%s\nNext stat: %d", oldstr, newstat)



I can't think of any case where this would be difficult, and it seems to me that reformatting the same string over and over again is a recipe for hard-to-solve bugs.

(No comment on the C++ stuff some others have posted; I'm not very familiar with the C++ ways.)

It becomes formatted many times since I send it to a function that is sometimes the "end-function" (drawing to screen) and sometimes not (forwarding the string to another function).

Maybe I should count the "extra parameters" (sent with the syntax "...") and only do formatting on the "char *" if there are any. Would that make sense? Now I always do the formatting regardless (i'm using va_list, va_start, va_end).

Advertisement
8 hours ago, JulieMaru-chan said:

Is there any particular reason you're formatting a string several times? It seems to me this is something you should be avoiding.

QFE.  Formatting a format string is a bad bad thing to do.  If you include any user input at all, you're opening a gaping hole (imagine a username of "%s").  It's as if you've said to yourself "how can I take one of the most insecure, error-prone, dangerous parts of the language and make it more error-prone, dangerous, and insecure?"  Then, of course you come here asking "I've made the most error-prone part of the language more error-prone and now I have an error, can I keep digging until I find my way out?"

Modifying format strings that get used elsewhere at some unknown time is implicitly modifying global state as a side-effect of your functions.  Instead, make your functions pure and have them returns already-formatted strings, only assembling them into larger strings when you have control and not as a global variable.

Stephen M. Webb
Professional Free Software Developer

It becomes formatted many times since I send it to a function that is sometimes the "end-function" (drawing to screen) and sometimes not (forwarding the string to another function).



Maybe I should count the "extra parameters" (sent with the syntax "...") and only do formatting on the "char *" if there are any. Would that make sense? Now I always do the formatting regardless (i'm using va_list, va_start, va_end).


So, why can't these functions you're sending the string to just not format the string that's sent to them, like in the example I posted? I'm still not understanding why you're formatting arbitrary strings. An example of one of these functions would be nice.

Ok the issue at hand is these functions:

                sprintf(help1, "Risk of hostilities: %d %%%%%%%%%%%%%%%%", www.ambushRisk[ambushMood][0]);
                sprintf(help2, "Risk of hostilities: %d %%%%%%%%%%%%%%%%", www.ambushRisk[ambushMood][1]);
 


sprintf(help1, "Risk of hostilities: %d %%%%%%%%%%%%%%%%", www.ambushRisk[ambushMood][0]);
sprintf(help2, "Risk of hostilities: %d %%%%%%%%%%%%%%%%", www.ambushRisk[ambushMood][1]);
gui.setPopupChoicesMouseover(gui.popupHolder.pos.x + 40, 610, help1, help2);


void gameGUI::setPopupChoicesMouseover(int x, int y, char * c0, char * c1)
{
	if (x){
		popupHolder.popupHelpX = x;
		popupHolder.popupHelpY = y;
	}

	if (c0 && c0[0] != 0) { sprintf(popupHolder.answerMouseover[0], c0); }
	if (c1 && c1[0] != 0) { sprintf(popupHolder.answerMouseover[1], c1); }
}

1. So first a sprintf to format the input.

2. Then a sprintf when I "store" the input (in setPopupChoicesHelp) in the gui class

3. Then another sprintf when the stored char array is sent to the drawing function to draw the text to screen when hoovering the button in question. And that function can also take "..."-parameters so I need a sprintf there as well :)

It seems every step doubles the amount of %-signs I need so I end up with an actual %-sign in the "end function."

Again, you've not once explained why you're using the most in-efficient in-secure method known to man in the C language.  Are you limited to C99 only?  You tagged this as C++, use C++ it has much easier, and much more secure methods to solve this problem.  And they've already been posted in this thread.  I'm not sure why you're still battling this fight which you're ultimately never going to win (it will always be very insecure and a possible source of serious bugs).

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement