Output sprintf snprintf sprintf_s and input scanf sscanf function detailed explanation

1. Use of sprintf snprintf sprintf_s function

As we all know, sprintf cannot check the length of the target string, which may cause many security problems , so it is recommended to use snprintf. Since snprintf replaced sprintf, I believe everyone will use snprintf a lot.

It is different under linux and windows. snprintf() is used under linux; _snprintf() is used under windows;

1、sprintf()

sprintf refers to the string formatting command.

函数声明为 
int sprintf(char *string, char *format [,argument,…]);
参数:
str为要写入的字符串;
format为格式化字符串,与printf()函数相同;
argument为变量。

sprintf is almost the same as printf in terms of usage, except that the destination of printing is different. The former prints to a string, while the latter outputs directly on the command line.

1. sprintf() prints an integer to a string

like:

sprintf(s, “%d”, 123); //print the integer 123 into a string and save it in s

sprintf(s, "%8x", 4567); // lowercase hexadecimal, 8 positions in width, right-aligned

2. When printing hexadecimal content, you usually want an equal-width format with 0s on the left

sprintf(s, "%08X", 4567); //generates: "000011D7"

It's very simple, just add a 0 in front of the number representing the width.

3. Control the printing format of floating point numbers

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, 6 digits after the decimal point are reserved, for example:

sprintf(s, “%f”, 3.1415926); //produces "3.141593"

4. Control the printing width and decimal places

"%m.nf" format, where m represents the width of the print and n represents the number of digits after the decimal point. for example:

    sprintf(s, “%10.3f”, 3.1415626); //产生:" 3.142"
    sprintf(s, “%-10.3f”, 3.1415626); //产生:"3.142 "
    sprintf(s, “%.3f”, 3.1415626); //不指定总宽度,产生:“3.142”

The C language does not detect the length of the array when operating on the array. If the length of str is not enough, sprintf() can easily cause buffer overflow and bring unexpected consequences. Hackers often use this weakness to attack seemingly safe systems:

#include <stdio.h>
main()
{
    char buf[10];
    sprintf(buf, "The length of the string is more than 10")
    printf("%s", buf);
}

The running result is: "The length of the string is more than 10",

At the same time, the system prompts that the program has stopped. The reason is that the length of the string to be written exceeds the length of buf, causing a buffer overflow.

Using snprintf() instead of sprintf() will solve this problem well.

2、snprintf()

The snprintf() function is used to write formatted data to a string

The prototype is: int snprintf(char *str, int n, char * format [, argument, …]);

Parameters: str is the string to be written; n is the maximum number of characters to be written, if it exceeds n, it will be truncated; format is the format string, which is the same as the printf() function; argument is a variable.

Return value: If successful, return the string length of the parameter str; if failed, return -1, and the cause of the error is stored in errno.

snprintf() has one more parameter than sprintf(), which can control the length of the string to be written, which is safer. As long as you pay attention, it will not cause buffer overflow.

 #include <stdio.h> 
 int main()
 {
  char buffer[50];
  char* s = "runoobcom";
  int j = snprintf(buffer, 6, "%s\n", s);// 读取字符串并存储在 buffer 中
  printf("string:\n%s\ncharacter count = %d\n", buffer, j); // 输出 buffer及字符数
   return 0;
  }

output result

string:

abcde

character count = 10

For the return value, it should be noted that the return value of snprintf is the length of the string to be written (that is, the source string), not the length of the actually written string. like:

char test[8];
int ret= snprintf(test,5,"1234567890");
printf("%d|%s\n",ret,test);
#include <stdio.h>
 
int main () {
  char a[16];
  size_t i;
  char path[216] = {0};
  i = snprintf(a, 13, "%012d", 12345);  // 第 1 种情况
  printf("i = %lu, a = %s\n", i, a);    // 输出:i = 12, a = 000000012345
 
  i = snprintf(a, 9, "%012d", 12345);   // 第 2 种情况
  printf("i = %lu, a = %s\n", i, a);    // 输出:i = 12, a = 00000001
 
  i = snprintf(path, sizeof(path), "%s/%s.%s.so","/system/lib64/hw/love", "tanghanyue", "default");
  printf("i = %lu, path = %s\n", i, path);    // 输出:i = 43, path = /system/lib64/hw/love/tanghanyue.default.so
  return 0;
}

The output result is:

10|1234

3、sprintf_s

int sprintf_s(char *restrict buffer, rsize_t bufsz,

const char *restrict format, ...);

Format data to a string, sprintf_s() is a safe version of sprintf(), avoiding the overflow risk of sprintf() by specifying the buffer length.

sprintf_s was originally only supported by the windows compiler, not a standard function in C.

Support for this function has been added to the C11 standard, but it is optional and not mandatory.

C11 stipulates that if the compiler implements the __STDC_LIB_EXT1__ macro, it must support the implementation of this function.

The gcc compiler only partially supports the C11 standard. I tested that __STDC_LIB_EXT1__ was not implemented in the gcc 5.4.0 version of ubuntu.

In gcc, the snprintf function can be used to simply replace sprintf_s, but note that there are certain differences in the implementation of the two, and they are not exactly the same.

int snprintf( char *restrict buffer, int bufsz,

const char *restrict format, ... );

Two, scanf sscanf function use

1、scanf()

The scanf function is a standard library function, and its function prototype is in the header file "stdio.h". Like the printf function, the C language also allows the stdio.h file not to be included before using the scanf function.

The general form of the scanf function is: scanf("format control string", address list);

scanf(“%d”,&a);

& is an address operator, and &a is an expression whose function is to find the address of a variable.

Indicates the type of input data, and its format and meaning are as follows

%d: Enter a decimal integer

%o: Enter an octal integer

%x: Enter a hexadecimal integer

%u: input unsigned decimal integer

%f or e: Enter a real number (in decimal form or exponential form)

%c: Enter a single character

%s: input string

scanf(“%d %*d %d”,&a,&b);

It is used to represent the input item, and the corresponding variable is not assigned after reading, that is, the input value is skipped.

When the input is: 1 2 3, 1 is assigned to a, 2 is skipped, and 3 is assigned to b.

scanf(“%d%d”,&r,&c);

will accept the input 10 20, but fail on 10,20.

2、 sscanf()

The role of sscanf(): Read data that matches the specified format from a string.

**Define function int sscanf (const char *str, const char * format,…); **Function description:

sscanf() will convert the string of the parameter str according to the parameter format string and format the data. For the format conversion form, please refer to scanf(). The converted result is stored in the corresponding parameter.

1. Description

sscanf is usually used to parse and convert strings, and its format definition is flexible and changeable, which can realize very powerful string parsing functions.

Prototype of sscanf

#include <stdio.h>

int sscanf(const char *str, const char *format, ...);

str: string to be parsed;

format: string format description;

This is followed by a sequence of variable number of pointer parameters storing the parsed data.

2. Example usage

1. Basic usage of sscanf

integer conversion

int year, month, day;
int converted = sscanf("20191103", "%04d%02d%02d", &year, &month, &day);
printf("converted=%d, year=%d, month=%d, day=%d/n", converted, year, month, day);

Output result:

converted=3, year=2019, month=11, day=03

"%04d%02d%02d" is the format used to parse the string, % indicates the start of format conversion, d indicates conversion to an integer, 04 is used as a modification of d, indicating that this is an integer with a length of 4 digits, and padding with 0 if it is less than 4 digits.

The example returns a result equal to 3, which means that 3 data have been converted successfully. The number of successful conversions depends on the parsed string and its conversion format. If we change the format in the example to "%04d%02d", then sscanf will only return 2, and the value of day will not be changed by sscanf.

floating point conversion

double longitude, latitude;
int converted = sscanf("113.123456789 31.123456789", "%lf %lf", &longitude, &latitude);
printf("converted=%d, longitude=%.9lf, latitude=%lf/n", converted, longitude, latitude);

Output result:

converted=2, longitude=113.123456789, latitude=31.123457

In the format string of sscanf, f indicates that this is a floating-point number, and its modifier l indicates that this is a double floating-point number.

2. Advanced usage of sscanf

number + string

char str[32] = "";
sscanf("123456abcdedf", "%31[0-9]", str);
printf("str=%s/n", str);

Output result:

str=123456

In the above format, [0-9] means that this is a string containing only characters 0-9, and the number 31 modifier is used in front of it to indicate the maximum length of the string buffer (this is also the most criticized place of sscanf, which is prone to buffer overflow errors. In fact, sscanf can avoid buffer overflow, as long as you write any string parsing format, pay attention to the limit of its buffer size).

char str[32] = "";
sscanf("123456abcdedf", "%31[0-9a-z]", str);
printf("str=%s/n", str);

Output result:

str=123456abcdedf

Added description of az in format[].

Example using ^:

char str[32] = "";
sscanf("123456abcdedf", "%31[^a-z]", str);
printf("str=%s/n", str);

Output result:

str=123456

Adding in [] means the opposite meaning, the above [az] means a string that does not contain any az.

Example using *:

char str[32] = "";
int ret = sscanf("123456abcdedf", "%*[0-9]%31[a-z]", str);
printf("ret=%d, str=%s/n",ret, str);

Output result:

right=1, str=abcdedf

Adding * modification indicates a data that is ignored, and there is no need to prepare space for it to store the analysis result. As in the above example, we only use str as a parameter to store the analysis result of %31[az], and sscanf only returns 1, indicating that only one data has been analyzed.

After mastering how to use [], ^, *, we will find that sscanf is such a powerful tool. Many places that we thought we had to use regular expressions can be realized with sscanf.

The specific usage of sscanf:

#include<stdio.h>
#include<stdlib.h>
#include<string.h> 
int main()
{
     char str[100];
     //用法一:取指定长度的字符串
     sscanf("12345","%4s",str);
     printf("str=%s",str);
     
      //用法二:格式化时间
     int year,month,day,hour,minute,second;
     sscanf("2021/10/18 14:55:34","%d/%d/%d %d:%d:%d",&year,&month,&day,&hour,&minute,&second);
     printf("time = %d-%d-%d %d:%d:%d\n",year,month,day,hour,minute,second); 
     
     //用法三:读入字符串
     sscanf("12345","%s",str);
     printf("str = %s\n",str);
     
     //用法四:%*d 和 %*s 加了星号 (*) 表示跳过此数据不读入. (也就是不把此数据读入参数中)
     sscanf("12345acc","%*d%s",str);
     printf("str = %s\n",str);
     sscanf("hello, world", "%*s%s", buf);
     printf("%s\n", buf);
     
     //用法五:取到指定字符为止的字符串。如在下例中,取遇到任意小写字母为止的字符串。
     sscanf("123456abcdedf","%[^a-z]",buf);
     printf("%s\n",buf);
     // %*s表示第一个匹配到的%s被过滤掉,即hello,被过滤了,如果没有空格则结果为NULL。
       
     //用法六:取到指定字符集为止的字符串。如在下例中,取遇到小写字母为止的字符串。
     sscanf("12345+acc121","%[^a-z]",str);
     printf("nstr = %s\n",str);
     
     return 0;
}

output:

str=1234

time = 2021-10-18 14:55:34

str = 12345

str = acc

world

str = 123456

str = 12345+

Guess you like

Origin blog.csdn.net/qq_20853741/article/details/128879573