用C屏蔽打印的字符串

时间:2017-02-07 21:03:43

标签: c string

是否可以仅使用printf函数来屏蔽字符串?

存在于char数组中的静态字符串。用户将输入一个数字,该数字是用户想要打印的字符数。假设字符串是14个字符并且用户输入20,是否可以屏蔽字符串,以便仅使用printf函数用'*'替换最后6个字符?

1 个答案:

答案 0 :(得分:4)

如果你满足于空间而不是想要星号,那么你可以直接进行。

由于你需要星号,答案是“不是真的” - 至少,如果所需的填充量可以任意大。如果填充量永远不会超过N个字节,您可以创建一个N个星号的字符串并解决它。

如果源字符串长于用户指定的N,则您的问题未指定会发生什么。此实现假定字符串的前N个字符应打印而不进行屏蔽。

#include <stdio.h>
#include <string.h>

/* For inclusion in a header file */
extern void mask_string(const char *str, int n, char pad);

static inline int min(int x, int y) { return (x < y) ? x : y; }
static inline int max(int x, int y) { return (x > y) ? x : y; }

void mask_string(const char *str, int n, char pad)
{
    char buffer[n+1];
    memset(buffer, pad, n);
    buffer[n] = '\0';
    int len1 = min(strlen(str), n);
    int len2 = max(n - (int)strlen(str), 0);
    printf("%.*s%.*s", len1, str, len2, buffer);
}

/* Test code */

static void test_mask_string(const char *data, int i)
{
    printf("%2d: [", i);
    mask_string(data, i, '*');
    putchar(']');
    putchar('\n');
}

int main(void)
{
    char data[] = "suppose the string";
    for (int i = 11; i < 24; i++)
        test_mask_string(data, i);
    return 0;
}

示例输出

使用GCC 6.2.0在macOS Sierra 10.12.3上测试。

11: [suppose the]
12: [suppose the ]
13: [suppose the s]
14: [suppose the st]
15: [suppose the str]
16: [suppose the stri]
17: [suppose the strin]
18: [suppose the string]
19: [suppose the string*]
20: [suppose the string**]
21: [suppose the string***]
22: [suppose the string****]
23: [suppose the string*****]

仅使用printf()

显示的代码有5行代码加上两行内联(单行)函数。我宁愿不消除这些功能,但只要你总是想要星号而且不要超过(比方说)其中的80个,那么你可以将其减少到:

#include <stdio.h>
#include <string.h>

/* For inclusion in a header file */
extern void mask_string(const char *str, int n);

static inline int min(int x, int y) { return (x < y) ? x : y; }
static inline int max(int x, int y) { return (x > y) ? x : y; }

void mask_string(const char *str, int n)
{
    printf("%.*s%.*s", min(strlen(str), n), str,
                       max(n - (int)strlen(str), 0),
                       "****************************************"
                       "****************************************");
}

/* Test code */

static void test_mask_string(const char *data, int i)
{
    printf("%2d: [", i);
    mask_string(data, i);
    putchar(']');
    putchar('\n');
}

int main(void)
{
    char data[] = "suppose the string";
    for (int i = 11; i < 24; i++)
        test_mask_string(data, i);
    return 0;
}

此测试输出与之前相同。

注意使用字符串文字连接。如果我要走这条路,我很想添加一个断言来确保代码没有请求太多的星号:

assert(max(n - strlen(str), 0) <= 80);

甚至使用宏:

#define STARS "****************************************" \
              "****************************************"

assert(max(n - strlen(str), 0) < sizeof(STARS));
printf("%.*s%.*s", min(strlen(str), n), str,
                   max(n - strlen(str), 0), STARS);

显然,如果你坚持不使用内联函数,你可以在参数列表中将它们写出printf()。我认为这不会使代码更清晰。