我的字符串末尾的随机字母?

时间:2017-07-12 01:36:50

标签: c arrays string projects

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等......只是想知道这里的问题是什么。

我的问题与提到的问题不一样。我不是试图在另一个单词的中间插入一个单词,我试图将一个单词分成两半并将这两个单词放在两个字符串中。

5 个答案:

答案 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() @BlastfurnaceYMMV

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拆分为1234很容易,但是如何拆分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(...)

所示

解决方案尽可能接近原始代码。它们适用于偶数,奇数和空字符串。

请注意memcpystrncpy解决方案的对称性。

#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);
}