在C语言中,打印字符数组的部分内容最简单的方法是什么?

36
假设我有一个char* str = "0123456789",我想剪去前三个和后三个字母,只打印中间的部分,最简单且最安全的方法是什么?
现在的关键是:要剪切的部分和要打印的部分大小是可变的,因此我可能会有一个非常长的char*,或者一个很小的。
5个回答

70
你可以使用 printf() 函数,并搭配一个特殊的格式字符串:
char *str = "0123456789";
printf("%.6s\n", str + 1);
%s 的精度转换说明符指定要打印的最大字符数。您还可以在运行时使用变量来指定精度:
int length = 6;
char *str = "0123456789";    
printf("%.*s\n", length, str + 1);

在这个例子中,* 用于指示下一个参数 (length)将包含%s 转换的精度,相应的参数必须是int
可以使用指针算术来指定起始位置,就像我上面所做的那样。 [编辑] 还有一点,如果您的字符串比精度说明符短,则将打印较少字符,例如:
int length = 10;
char *str = "0123456789";
printf("%.*s\n", length, str + 5);

将会打印出 "56789"。如果你想总是打印一定数量的字符,那么需要同时指定最小字段宽度和精度:

printf("%10.10s\n", str + 5);

或者
printf("%*.*s\n", length, length, str + 5);

将打印:

"     56789"

您可以使用减号将输出左对齐到字段中:
printf("%-10.10s\n", str + 5);

最后,最小字段宽度和精度可以不同,即

printf("%8.5s\n", str);

该代码将在8个字符的字段中右对齐打印最多5个字符。


这很酷。我今天早些时候才了解到字符串截断(我想我一直都是用实际的字符串来进行子字符串操作,而不是使用printf)。那么为什么整数不能这样做呢?例如,为什么不能说printf("%.2d", 123);只打印23printf("%-.2d", 123);只打印12:-| - Synetech

9

Robert Gamble和Steve各自拥有大部分的组件。 将它们组装成一个整体:

void print_substring(const char *str, int skip, int tail)
{
    int len = strlen(str);
    assert(skip >= 0);
    assert(tail >= 0 && tail < len);
    assert(len > skip + tail);
    printf("%.*s", len - skip - tail, str + skip);
}

示例的调用方法:

print_substring("0123456789", 1, 3);

1

如果您不介意修改数据,您可以进行一些指针算术运算。这是假设str是一个char指针而不是数组的情况:

char string[] = "0123456789";
char *str = string;

str += 3; // "removes" the first 3 items
str[4] = '\0'; // sets the 5th item to NULL, effectively truncating the string

printf(str); // prints "3456"

1
如果您可以保证字符串可写,则是“OK”的。但是,由于不一定需要修改字符串,最好不要这样做。 - Jonathan Leffler
1
在清除之前,您应该保存旧值,然后在清除后恢复它。 - Jonathan Leffler

0

这里有一个干净简单的子字符串函数,我从我的个人库中挖掘出来,可能会很有用:

char *
substr(const char *src, size_t start, size_t len)
{
  char *dest = malloc(len+1);
  if (dest) {
    memcpy(dest, src+start, len);
    dest[len] = '\0';
  }
  return dest;
}

这个函数很可能是不言自明的,它接受一个字符串、一个起始位置(从零开始)和一个长度,并返回原始字符串的子串或空指针(如果 malloc 失败)。当内存不再需要时,调用者可以使用 free 释放返回的指针。为了符合 C 的精神,该函数不验证提供的起始位置和长度。


-2

我相信printf有一些神奇的技巧,可以仅打印特定数量的字符,但这不是常见的理解或使用方式。我们曾尝试在之前的工作中实现它,但无法始终使其正常工作。

我的做法是先保存一个字符,在字符串中将其清空,打印后再重新保存回来。


看看我的printf示例,我已经使用这种方法很长时间了,它总是对我产生一致的效果。 - Robert Gamble
当源字符串是常量时,save-null-restore技巧会惨败。不要这样做。 - Jonathan Leffler
Robert: 你确定这个格式(例如:%.*)适用于任何C编译器吗? - botismarius
1
@botismarius:它将与支持C89或C99的任何C库一起工作,它已成为标准20年,来自C89规范: “字段宽度或精度(或两者)可以用星号*表示,而不是数字字符串。在这种情况下,int参数提供字段宽度或精度。” - Robert Gamble
我很高兴在看到这个例子有多简单后被降级了。在我们的情况下,我们遇到了一些问题,无法在我们需要的所有平台上始终有效地使用“使用前一个参数的字符串长度”功能。那是我最好的回忆。 - Dan Olson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接