Explanation of sprintf usage in C Language 21:48:37
Tags: original sprintf files in C language, which can be reproduced. During reprinting, you must mark the original source, author information, and statement in the form of a hyperlink. Otherwise, legal liability will be held. Http://suguiyang.blog.51cto.com/1035725/416990
Printf may be the second function that many programmers encounter when learning C language (I guess the first function is main). It is naturally an old friend. However, do you know much about this old friend? Do you know more about sprintf? When constructing various types of data into strings, the powerful features of sprintf seldom disappoint you.
Since sprintf and printf have almost the same usage, but the printing destination is different, the former is printed into the string, and the latter is directly output on the command line. This also makes sprintf much more useful than printf. So this article focuses on sprintf, which is sometimes interspersed with pritnf.
Sprintf is a variable parameter function, which is defined as follows:
Int sprintf (char * buffer, const char * Format [, argument]...);
In addition to the fixed types of the first two parameters, you can take over multiple parameters later. Its essence is obviously on the second parameter: Format String.
Both printf and sprintf use formatted strings to specify the string format. Some format specifiers (format specifications) starting with "%" are used inside the format string to occupy a position, the variable is provided in the variable parameter list, and the function will replace the specifier with the variable at the corresponding position to generate the string that the caller wants.
1. format the numeric string
One of the most common applications of sprintf is to print Integers to strings. Therefore, spritnf can replace ITOA in most cases. For example:
// Print the integer 123 into a string and save it in S.
Sprintf (S, "% d", 123); // generate "123"
You can specify the width. If the width is insufficient, spaces are filled on the left:
Sprintf (S, "% 8d % 8d", 123,456 7); // generate: "123 4567"
Of course, you can also align left:
Sprintf (S, "%-8d % 8d", 123,456 7); // generate: "123 4567"
You can also print the data in hexadecimal format:
Sprintf (S, "% 8x", 4567); // lowercase hexadecimal notation, with 8 width positions and right alignment
Sprintf (S, "%-8x", 4568); // in hexadecimal notation, the width occupies 8 positions and is left aligned.
In this way, the hexadecimal string of an integer is easy to obtain, but when printing the hexadecimal content, we usually want an equal-width format with 0 on the left, what should we do? Simply add 0 to the number that represents the width.
Sprintf (S, "% 08x", 4567); // generate: "201711d7"
You can also use this left-side 0 Complement Method to print the 10-in-hexadecimal format with "% d" above.
Pay attention to a symbol extension problem: for example, if we want to print a short INTEGER (short)-1 memory hexadecimal representation, on the Win32 platform, A short type occupies 2 bytes, So we naturally want to print it with 4 hexadecimal numbers:
Short Si =-1;
Sprintf (S, "% 04x", Si );
Why is "ffffffff" generated? Because spritnf is a Variable Parameter Function, except the first two parameters, the following parameters are not of type security, there is no way for a function to know whether a 4-byte integer or a 2-byte short integer is pressed in the parameter stack before the function call through a "% x "., therefore, a 4-byte processing method is adopted, which leads to the symbol extension during parameter pressure stack, which is a 32-bit integer-1. When printing, the four locations are insufficient, print out the 8-bit 16 hexadecimal values of 32-bit integer-1. If you want to see the original form of Si, you should let the compiler do 0 extension instead of symbol extension (during expansion, the left side of the binary complement 0 instead of the sign bit ):
Sprintf (S, "% 04x", (unsigned short) Si );
You can. Or:
Unsigned short Si =-1;
Sprintf (S, "% 04x", Si );
Sprintf and printf can also print integer strings in octal, using "% O ". Note that both the octal and hexadecimal formats do not print negative numbers. They are all unsigned. In fact, they are the direct hexadecimal or octal representation of the variable's internal code.
2. Control the floating point printing format
The printing and format control of floating point numbers is another common function of sprintf. Floating Point Numbers are controlled by the format character "% F". By default, the six digits after the decimal point are retained, for example:
Sprintf (S, "% F", 3.1415926); // generate "3.141593"
But sometimes we want to control the print width and decimal places by ourselves, then we should use the format "% m. NF", where M indicates the print width, N indicates the number of digits after the decimal point. For example:
Sprintf (S, "% 10.3f", 3.1415626); // generate: "3.142"
Sprintf (S, "%-10.3f", 3.1415626); // generate: "3.142"
Sprintf (S, "%. 3f", 3.1415626); // The total width is not specified, resulting in: "3.142"
Pay attention to one question, you guess
Int I = 100;
Sprintf (S, "%. 2f", I );
What will it do? 100.00 "? Right? Try it on your own and try the following:
Sprintf (S, "%. 2f", (double) I );
The first one is definitely not the correct result, because, as mentioned above, the caller does not know that the format controller corresponding to I is "% F" when the parameter is pressed ". When a function is executed, the function itself does not know that the number pushed to the stack in the current year is an integer, so the four bytes that saved the integer I were forcibly interpreted as a floating-point number.
However, if someone is interested in manually encoding a floating point number, you can use this method to check whether the result of your manual arrangement is correct. J
Character/ASCII code comparison
We know that in C/C ++, char is also a common scalable type. In addition to the word length, it has no essential difference with short, Int, and long, it is used to represent characters and strings. (This type may be called "Byte" in the past, and now we can use byte or short to define char through typedef according to the actual situation, which is more appropriate)
Therefore, print a character using "% d" or "% x" to obtain its 10-or 16-digit ASCII code. In turn, print an integer using "% C" to see its ASCII characters. The following section prints the ASCII code table of all visible characters to the screen (printf is used here, note that "#" and "% x" are automatically prefixed with "0x" in hexadecimal notation ):
For (INT I = 32; I <127; I ++ ){
Printf ("[% C]: % 3d 0x % # 04x/N", I, I );
}
3. connection string
Since the sprintf format control string can insert various things and "connect them together", it can naturally connect strings, which can replace strcat in many occasions, but sprintf can connect multiple strings at a time (it can also insert other content in them at the same time, in short, it is very flexible ). For example:
Char * Who = "I ";
Char * Whom = "csdn ";
Sprintf (S, "% s love % S.", who, whom); // generate: "I love csdn ."
Strcat can only connect strings (an array of characters ending with '/0' or a character buffer, null-terminated-string), but sometimes we have two character buffers, they do not end with '/0. For example, many character arrays returned from third-party library functions, and hidden streams read from hardware or network transmission, they may not end with a corresponding '/0' after each character sequence. If you connect directly, whether sprintf or strcat will certainly lead to illegal memory operations, and strncat also requires at least the first parameter to be null-terminated-string. What should we do? We naturally remember that the width can be specified when we first introduced printing integers and floating-point numbers, and the strings are the same. For example:
Char A1 [] = {'A', 'B', 'C', 'D', 'E', 'F', 'G '};
Char A2 [] = {'h', 'I', 'J', 'k', 'l', 'M', 'n '};
If:
Sprintf (S, "% S % s", a1, a2); // don't do that!
In, something went wrong. Can it be changed:
Sprintf (S, "% 7 S % 7 s", a1, a2 );
It's not good where to go. The correct one should be:
Sprintf (S, "%. 7 S %. 7 s", a1, a2); // generate: "abcdefghijklmn"
This can be analogous to printing the "% m. NF ", in" % m. in "ns", "M" indicates the width occupied (when the string length is insufficient, fill in spaces. If the length exceeds the limit, print it according to the actual width). "N" indicates the maximum number of characters used from the corresponding string. Generally, M is useless when printing strings, but n is usually used after the dot. Naturally, you can only take part of the characters before and after:
Sprintf (S, "%. 6 S %. 5 s", a1, a2); // generate: "abcdefhijkl"
In many cases, we may also want the numbers in these format controllers to specify length information to be dynamic, rather than static, because many times, when the program is running, it will know exactly how many characters in the character array need to be taken. This dynamic width/precision setting function is also taken into account in the implementation of sprintf, sprintf uses "*" to occupy a position that originally requires a constant number with a specified width or accuracy. Similarly, the actual width or accuracy can be provided like other printed variables, so the preceding example can be changed:
Sprintf (S, "%. * S %. * s", 7, A1, 7, A2 );
Or:
Sprintf (S, "%. * S %. * s", sizeof (A1), A1, sizeof (A2), A2 );
In fact, the printed characters, integers, and floating-point numbers described above can all dynamically specify the constant values, such:
Sprintf (S, "%-* D", 4, 'A'); // generate "65"
Sprintf (S, "% #0 * X", 8,128); // generate "0x000080", "#" generate 0x
Sprintf (S, "% *. * F", 10, 2, 3.1415926); // generate "3.14"
4. Print the address information
Sometimes, when debugging a program, we may want to view the addresses of some variables or members. Because the addresses or pointers are only 32-bit numbers, you can print the unsigned integers "% u:
Sprintf (S, "% u", & I );
However, people usually prefer to use hexadecimal instead of hexadecimal to display an address:
Sprintf (S, "% 08x", & I );
However, these are indirect methods. For address printing, sprintf provides a special "% P ":
Sprintf (S, "% P", & I );
I think it is actually equivalent:
Sprintf (S, "% 0 * X", 2 * sizeof (void *), & I );
5. Use the sprintf Return Value
Few people pay attention to the return values of the printf/sprintf function, but sometimes it is useful. spritnf returns the number of characters that the function call finally prints to the character buffer. That is to say, after each sprinf call ends, you do not need to call strlen again to know the length of the result string. For example:
Int Len = sprintf (S, "% d", I );
For a positive integer, Len is equal to the 10-digit digits of the integer I.
The following is a complete example, which generates a random number between 10 [0,100) and prints them into an array of characters (s) separated by commas.
# Include <stdio. h>
# Include <time. h>
# Include <stdlib. h>
Int main (){
Srand (time (0 ));
Char s [64];
Int offset = 0;
For (INT I = 0; I <10; I ++ ){
Offset + = sprintf (S + offset, "% d,", Rand () % 100 );
}
S [offset-1] = '/N'; // Replace the last comma with a line break.
Printf (s );
Return 0;
}
Imagine that when you extract a record from the database and want to connect each of their fields into a string according to certain rules, you can use this method. Theoretically, it should be more efficient than the continuous strcat, because each call to strcat needs to first find the last '/0' position, and in the example given above, every time we use the sprintf return value to write down this position directly.
6. FAQs about using sprintf
Sprintf is a variable parameter function, which often causes problems when used, and as long as there is a problem, it is usually a memory access error that can cause the program to crash, but fortunately the problems caused by sprintf misuse are serious, but it is easy to find out, nothing more than a few situations, usually with the eyes of the error code to see a few more eyes. The first parameter of buffer overflow is too short. Of course, it may also be a problem with the following parameters. We recommend that you be careful with the corresponding parameters. When printing a string, try to use the "%. Ns" format to specify the maximum number of characters. I forget that the first parameter is too low-level to avoid low-level issues. I am too familiar with printf. // It is common. :. (An error occurred while changing the parameter.
Generally, you forget to provide variable parameters corresponding to a certain format character, which leads to misplacement of all subsequent parameters. Check the parameters. Are all parameters corresponding to "*" provided? Do not map an integer to a "% s". The compiler will think that you are deceiving her too much (the compiler is the mother of OBJ and exe, which should be a female: P ).
7. strftime
Sprintf also has a good cousin: strftime, which is specially used to format the time string. Its usage is very similar to that of her cousin. It is also a lot of format control characters, but after all, the girl's family is fine, she also needs the caller to specify the maximum length of the buffer, probably to shirk responsibility in case of problems. Here is an example:
Time_t t = time (0 );
// Generate a string in the format of "YYYY-MM-DD hh: mm: SS.
Char s [32];
Strftime (S, sizeof (s), "% Y-% m-% d % H: % m: % s", localtime (& T ));
Sprintf can also find its Zhiyin in MFC: cstring: format. strftime also has her same path in MFC: ctime: format, the code used to write is more elegant because of the sponsorship of the object-oriented program.