【问题标题】:Spilt a string into half and join it with another string将一个字符串分成两半并将其与另一个字符串连接
【发布时间】:2015-11-04 08:10:21
【问题描述】:

我想问是否说我有一个字符串“abcdefgh”,我想将其减半变成“abcd”和“efgh”并将其存储到他们自己的字符串中说我称之为“UpperHalf”和“LowerHalf”。所以这样做的方法是首先使用 strlen() 找出我输入的长度和一半?然后我需要使用 strcpy() 并将其复制到各自的字符串中,对吗?

实际上我什至不知道我的代码是否有意义。任何人都可以给我一些cmets吗?

我意识到我只需要考虑偶数输入,这意味着我不需要担心奇数输入。以前我试图将一维字符串分成两半,然后用其他东西 strcat 它。但是现在我得到了一系列以二维数组格式存储的输入字符串。在这种情况下,我如何检索这些字符串并像之前的 1d 情况一样操作它们?我认为我不需要使用 for 循环?我可以只指向行吗?

int d = strlen(str); // just an example where str = the characters inside my string
strcpy(temp, &str[0]); // store original string into a temp string starting from 0 to \0
str[d/2] = '\0';
strcpy(UpperHalf, &str[0]); // starts copying from position 0 to \0 which is the half way point
str[0] = temp;  //revert back to normal -> Does this line even make sense?
strcpy(LowerHalf, &str[d/2]);

【问题讨论】:

  • 将“/0”替换为“\0”
  • 谢谢。我纠正了它,但从逻辑上讲,有什么 cmets 吗?有点第一次做字符串。
  • 知道数组会自然衰减为指向其第一个元素的指针吗?这意味着如果你有一个数组str 并将它传递给一个带指针的函数,编译器将传递的内容实际上与&str[0] 相同。因此,您不必明确说明,只需传递 str 即可。

标签: c string split


【解决方案1】:

是的,您肯定需要考虑奇数字符串的长度。有一些代码方法可以将其向上或向下舍入(以便第一个或第二个字符串具有额外的字符),但您需要决定您希望它采用哪种方式。

查看您的代码,我建议不需要使用临时字符串。您可以直接从原始“str”复制并节省内存和处理器开销。将需要进行一些更改: 目前,您正在用 '\0' 字符覆盖源字符串中的一个字符,而您的第二个 strcpy 将从该 '\0' 开始,这将返回一个零长度字符串。 要复制固定数量的字符,您可以使用 strncpy,它通过简化代码并保持清晰,在此处比 strcpy 工作得更好。 不要忘记用 \0 终止你的字符串,或者你可以像我在这里一样用 0 值初始化缓冲区。

因此,示例可能如下所示:

char UpperHalf[MAX_LENGTH];
char LowerHalf[MAX_LENGTH];

int l = strlen(str);
int half = l / 2;
memset(LowerHalf, '\0', MAX_LENGTH);
strncpy(LowerHalf, str, half);
memset(UpperHalf, '\0', MAX_LENGTH);
strncpy(UpperHalf, str + half, l - half);

这会将奇数长度字符串的较长部分放入 UpperHalf 字符数组。 为了使代码安全,您还应该考虑进行长度比较,以确保所有字符串都适合所提供的缓冲区(至少有一个字符用于结束 \0 字符的字符串)。

【讨论】:

  • 表达式L / 2 是一个整数除法,将产生一个整数。我认为您在这里不需要浮点运算。只需将L/2 用作左侧子字符串,将L - L/2 用作右侧子字符串。 (我在这里使用了大写的 ell,否则它看起来太像小数的二分之一了。)
  • 是的,这也可以。为了保持整洁,我想将第一个除法存储到一个临时变量中: int lowHalf = L / 2;然后另一半的减法将明确为 L - lowHalf。如果仅将其中一个四舍五入,则使用两个单独的除法可能会出错。请注意,如果完全按照描述完成,这种方法会将短字符串放入 LowerHalf。
  • “太”是什么意思?你的方法行不通。 (或者,更温和地说,它只在理论上有效。)假设L 是7。那么L/2 是3,而不是3.5,因为这是一个整数除法。 3 + 0.5 是 3.5,在转换为 int 时将再次被截断为 3。你可以说L/2.0 + 0.5 将中间元素移动到左子数组。但这可以表示为(L + 1) / 2,您不需要任何浮点数学运算。
  • 确认是的,当然你是对的。我在类型提升的语言上花了太长时间!
  • 顺便说一句,对于代码的 memset 部分,您正在使用 '\0' 初始化整个数组,对吗?但是如果你为下半部分做 strncpy,strncpy(LowerHalf, str, half);将复制str中的字符,从0-4?在长度为 8 个字符的情况下。但是对于上半部分,l-half 不也会给我 4 并且我不会从 0-4 复制吗?
【解决方案2】:

是的,必须先用strlen得到输入字符串的长度,然后减半得到upper_half的长度:

size_t length = strlen(str);
size_t upper_length = length / 2;
size_t lower_length = length - upper_length;

在这种情况下,如果输入字符串的长度是奇数,那么由于整数除法,upper_length 将等于lower_length - 1,例如:

length == 3
upper_length == 3 / 2 == 1
lower_length == 3 - 1 == 2

在不修改原始字符串的情况下进行实际复制会更容易,就像您的代码所做的那样。

您必须分配空间来存储字符串一半的副本,并带有空终止符:

char *upper_half = malloc(upper_length + 1);
char *lower_half = malloc(lower_length + 1);

然后使用memcpy复制字符串数据:

memcpy(upper_half, &str[0], upper_length);
upper_half[upper_length] = '\0';

(同样适用于lower_half。)

strcpy 复制字符直到一个空字节,而memcpy 复制给定数量的字节。

【讨论】:

  • 嗨,你能解释一下 memcpy 和 memset 吗?因为我只学过普通的strcpy、strlen、strcmp和strcat。
  • @Morde: memcpy(destination, source, count)count 字节从source 复制到destination。如果您想使用 only strcpy 执行此操作,则基本上需要按照您的想法进行操作:将第一个字符串末尾的字符替换为空终止符,然后在您使用时恢复它重做。 char temp = str[upper_length]; str[upper_length] = '\0'; strcpy(upper_half, &str[0]); str[upper_length] = temp; strcpy(lower_half, &str[upper_length]); 但是,这段代码比直接复制数据的版本更难推理。
  • "... 而memcpy 复制给定数量的字节..." 但也有一个strncpy :) (哦,好吧,我发现它无论如何都从 OP 候选名单中丢失了。)
【解决方案3】:

虽然可以使用所有标准函数将下半部分/上半部分复制到单独的字符串中,但您也可以仅使用指针和单独的缓冲区来分割字符串以保存字符串的下半部分。

基本上,您可以找到字符串的长度,调整中点的奇数/偶数位置(如果需要总是但下半部分奇数长度上的附加字符),然后使用简单的循环复制到下半部分。在循环结束时,使用的指针指向上半部分(或者您可以简单地将指针用于中点的位置)。一个简短的例子是:

#include <stdio.h>

#define MAXC 64

int main (int argc, char **argv) {

    if (argc < 2 ) {
        fprintf (stderr, "error: insufficient input, usage: %s string\n",
                argv[0]);
        return 1;
    }

    char lower_half[MAXC] = {0};    /* array to hold lower_half */
    char *p = argv[1];              /* poiter to string         */
    char *pl = lower_half;          /* pointer to lower_half    */
    char *split = NULL;             /* pointer to split point   */
    size_t len = 0;                 /* string length            */

    for (; *p; p++);        /* find end of string   */
    len = p - argv[1];      /* get string length    */
    p = argv[1];            /* reset pointer        */
    split = p + len/2;      /* set split at middle  */
    if (len & 1) split++;   /* if odd, add 1        */

    for (; p < split; p++)  /* for each ch < split  */
        *pl++ = *p;         /* copy to lower_half   */
    *pl = 0;                /* null-terminate       */

    /* print results */
    printf ("\n lower_half : '%s'    upper_half : '%s'\n",
            lower_half, split);

    return 0;
}

输出

$ ./bin/str_half 123456789

 lower_half : '12345'    upper_half : '6789'

$ ./bin/str_half 1234567890

 lower_half : '12345'    upper_half : '67890'

不管你是使用指针还是使用strlenstrncpy、或memcpy等,只要确保你null-terminate分隔的字符串。上面,由于lower_half 在开始时被初始化为所有0,因此不需要显式的空终止。但是,最好始终确保您的代码以空值结尾的字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-15
    • 2015-06-18
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-17
    相关资源
    最近更新 更多