void split(char array[]) {
int length, length2, half;
char first_half[BUF], sec_half[BUF];
length = strlen(array);
length2 = length / 2;
length -= length2;
strncpy(first_half, array, length - 1);
strncpy(sec_half, (array + length), length2 - 1);
printf("%s\n", first_half);
printf("%s\n", sec_half);
}
如果输入是"人物",则输出: 的 Pe0z plcy等......只是想知道这里的问题是什么。
我的问题与提到的问题不一样。我不是试图在另一个单词的中间插入一个单词,我试图将一个单词分成两半并将这两个单词放在两个字符串中。
答案 0 :(得分:2)
OP的麻烦在于first_half[BUF], sec_half[BUF]
当然不是空字符终止 - strncpy()
的短暂出现。
strncpy( first_half, array, length);
// printf( "%s\n", first_half );
// alternative limited width print, even if `first_half` lacks a null character.
printf( "%.*s\n", length, first_half );
尝试将
字字符串分成两半并将两半放在两个字符串中。
下面是可变长度数组(VLA)方法。
我建议使用memcpy()
,因为对于长字符串而言,这通常是最快的,以免出错strncpy()
@Blastfurnace。 YMMV
void split(const char array[]) {
size_t a_length = strlen(array);
size_t l_length = a_length / 2;
size_t r_length = a_length - l_length;
char l_half[l_length + 1], r_half[r_length + 1]; // + 1 for null character
memcpy(l_half, array, l_length);
l_half[l_length] = '\0';
memcpy(r_half, array + l_length, r_length + 1); // +1 for null character
printf("<%s>\n", l_half);
printf("<%s>\n", r_half);
}
size_t
是无符号类型,是用于数组索引的正确大小的整数类型。 int
可能不够。请注意,strlen()
会返回size_t
类型。
如果只需要打印两半,则需要的代码不多:
void split_print(const char array[]) {
int half = strlen(array) / 2;
printf("%.*s\n", half, array);
printf("%s\n", array + half);
}
答案 1 :(得分:1)
由于我发现对性能存在担忧,我要说完全摆脱 strncpy 。
fist_half[l_length] = '\0';
while(l_length--)
first_half[l_length] = array[l_length];
可以通过一些索引修改将相同的方法应用于右侧。 这样你就可以摆脱 strncpy 的开销和 HEADACES 。
如果使用指针,代码可以进一步简化。
答案 2 :(得分:1)
尚未考虑的另一个问题是“如何处理具有奇数个字符的单词?”。将1234
拆分为12
和34
很容易,但是如何拆分123
?您必须决定如何测试奇数/偶数并决定哪一半获得额外的字符(通常是前半部分,但这取决于您)。您还应该考虑拆分任何大小的字符串(并验证处理传递给您的函数的NULL指针或空字符串)。
要处理检查奇数/偶数长度,您需要做的就是检查little-endian系统的第1位长度,或者为了完全可移植性,只需使用 modulo 2
。如果第1位(在little-endian上)或len % 2
的结果是0
它是偶数,否则长度是奇数。 (如果很奇怪,只需在前半部分添加+1
个字符。)
如果您的编译器支持可变长度数组 C99扩展,问题就变成了声明两个VLA并让编译器处理工作的问题,例如
void split_vla (char *s)
{
if (!s || !*s) { /* validate parameter not NULL or empty-string */
fprintf (stderr, "error: s NULL or empty-string.\n");
return;
}
size_t l = strlen (s),
n = (l % 2 == 0) ? l / 2 : l / 2 + 1;
char s1[n + 1], s2[n + 1]; /* declare VLAs */
memcpy (s1, s, n); /* memcpy chars to each half */
memcpy (s2, s + n, l - n);
s1[n] = 0; /* affirmatively nul-terminate */
s2[l - n] = 0;
printf ("s : %s\ns1 : %s\ns2 : %s\n", s, s1, s2);
}
如果没有,您可以随时为每个半部分动态分配存储(如果您选择calloc
而不是malloc
,那么您的存储将初始化为全零(在每一半的末尾提供 nul-byte ),例如
void split_dyn (char *s)
{
if (!s || !*s) { /* validate parameter not NULL or empty-string */
fprintf (stderr, "error: s NULL or empty-string.\n");
return;
}
size_t l = strlen (s),
n = (l % 2 == 0) ? l / 2 : l / 2 + 1;
char *s1, *s2;
/* allocate storage for s1 & s2 and validate allocation */
if (!(s1 = calloc (n + 1, 1)) || !(s2 = calloc (n + 1, 1))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
memcpy (s1, s, n); /* memcpy chars to each half */
memcpy (s2, s + n, l - n);
printf ("s : %s\ns1 : %s\ns2 : %s\n", s, s1, s2);
free (s1); /* don't forget to free the memory you allocate */
free (s2);
}
根据编译器支持的内容,两种方式都可以。您可以像在VLA示例中一样使用malloc
并肯定地 nul-terminate 。另请注意,alloca
提供了与VLA相似的功能,但在数组范围内提供了更大的灵活性(这里不相关,因为VLA是使用函数范围声明但要注意其他方法)。试试这两个例子,如果你有其他问题,请告诉我。
示例使用/输出
$ ./bin/str_split_half 123456789
s : 123456789
s1 : 12345
s2 : 6789
$ ./bin/str_split_half 1234567890
s : 1234567890
s1 : 12345
s2 : 67890
$ ./bin/str_split_half 1
s : 1
s1 : 1
s2 :
答案 3 :(得分:0)
如果您使用0初始化缓冲区就足够了,如split1(...)
char first_half[BUF] = {0}; // whole buffer is full of zeroes
char sec_half[BUF] = {0};
然后终止将是自动的。
未初始化的缓冲区包含随机字符。
如果缓冲区未归零,则需要终止,如split2(...)
解决方案尽可能接近原始代码。它们适用于偶数,奇数和空字符串。
请注意memcpy
和strncpy
解决方案的对称性。
#include <stdio.h>
#include <string.h>
#define BUF 255
void split1(char array[], int bUseMemcpy)
{
/* use zeroed buffers to automatically terminated the copied strings */
int length, length2;
char first_half[BUF] = {0};
char sec_half[BUF] = {0};
length = strlen( array );
length2 = length / 2;
length -= length2;
if(bUseMemcpy)
memcpy( first_half, array, length);
else
strncpy( first_half, array, length);
if(bUseMemcpy)
memcpy( sec_half, (array + length), length2);
else
strncpy( sec_half, (array + length), length2);
printf( "<%s>\n", first_half );
printf( "<%s>\n", sec_half );
}
void split2(char array[], int bUseMemcpy)
{
/* Do not initialize the buffers
Use 0 to terminate the buffers after the copy */
int length, length2;
char first_half[BUF];
char sec_half[BUF];
length = strlen(array);
length2 = length / 2;
length -= length2;
if(bUseMemcpy)
memcpy( first_half, array, length);
else
strncpy( first_half, array, length);
first_half[length]=0; /*zero termination needed, since buffers are not initialized to 0*/
if(bUseMemcpy)
memcpy( sec_half, (array + length), length2);
else
strncpy( sec_half, (array + length), length2);
sec_half[length2]=0; // zero termination
printf( "<%s>\n", first_half );
printf( "<%s>\n", sec_half );
}
int main(void) {
split1("123456789",0);
split1("",1);
split2("people",0);
split2("1",1);
return 0;
}
输出:
<12345>
<6789>
<>
<>
<peo>
<ple>
<1>
<>
答案 4 :(得分:0)
有一种简单的方法可以在两条不同的行上输出字符串:使用printf
转换格式%.*s
。它打印字符串参数的初始部分:
void split(const char *array) {
int half = strlen(array) / 2;
printf("%.*s\n%s\n", half, array, array + half);
}