函数没有为数组赋值(使用指针运算)

时间:2016-10-09 22:38:38

标签: c arrays string pointers

我的程序应该读入两个字符串并以新字符串(3rd)打印为第一个字符串中的第一个字符,然后是第二个字符串中的第一个字符串,然后是第一个字符串中的第二个字符串,依此类推。较长字符串中的任何多余字符都放在最后。

这里是代码:

#include <stdio.h>
#include <string.h>
#define N 1000

void merge(char *s3, char *s1, char *s2);
int read_line(char *str, int n);

int main(void)
{
    char a[N], b[N], c[N];
    int num_chara, num_charb, num_charc, i;


    printf("Enter the first set of characters: ");
    num_chara = read_line(a, N);
    printf("Enter the second set of characters: ");
    num_charb = read_line(b, N);

    num_charc = num_chara + num_charb;

    merge(c, a, b);
    printf("Output: ");
    for (i = 0; i < num_charc; i++)
        printf("%c", c[i]);
    printf("\n");

    return 0;
}

void merge(char *s3, char *s1, char *s2)
{
    size_t low_limit, up_limit;
    int i;

    if (strlen(s1) < strlen(s2))
    {
        low_limit = strlen(s1);
        up_limit = strlen(s2);
    }
    else
    {
        low_limit = strlen(s2);
        up_limit = strlen(s1);
    }

    for (i = 0; i < low_limit; i++)
    {
        s3 = s1 + i;
        s3++;
        s3 = s2 + i;
        s3++;
    }

    if (strlen(s1) < strlen(s2))
    {
        for (i += 1;i < up_limit; i++ )
        {
            s3 = s2 + i;
            s3++;
        }
        *s3 = '\0';
    }
    else
    {
        for (i += 1;i < up_limit; i++ )
        {
            s3 = s1 + i;
            s3++;
        }
        *s3 = '\0';
    }
}

我的问题是,在main()中调用它时,打印第三个字符串会导致没有打印任何内容,就像第三个字符串是空的一样!

打印方法是正确的,因为我能够正确打印第1和第2个字符串。我无法弄清楚我在这里做错了什么,因为每一步的逻辑都对我有意义。虽然我是C的新手,但指针算法仍然让我很烦恼。

修改:

1)我很惊讶编译这个没有给我任何错误或警告(gcc)。

2)用* s3替换s3的赋值以及*(s1或s2 + i)使得该程序在大多数情况下都能正常工作。虽然现在输出中的最后几个字符我得到了意想不到的结果。感谢Christophe,但我正试图避免在此程序中使用任何数组索引。

1 个答案:

答案 0 :(得分:1)

哎哟!在merge()中,您正在进行指针运算而不是指定值。这是完全合法的,所以编译器不会抱怨:

例如:

    ...
    s3 = s1 + i;    // simply changes the pointer, not the zone pointed to 
    s3++;           // now the pointer 3 points to the address of a[i+1]
    ...             // the content of the string pointed by s3 is left unchanged

要解决此问题,您必须使用*[]取消引用指针:

    ...
    *s3 = s1[i];    // works on the character pointed to and not the pointer itself
    s3++;
    *s3 = s2[i];    // you could combine the two lines with *s3++ = s2[i]
    s3++;
    ...

重要提示:您的函数merge()非常不安全:此函数对数组的大小一无所知。如果ab已填满N-1个字符且结尾为'\0':该函数会将2*N-1个字符写入c,因此您会有缓冲区溢出破坏你的记忆。两个容易修复致命漏洞:

  • c的尺寸更改为2*N
  • 将函数签名更改为void merge_s (char *s3, char *s1, char *s2, size_t n),其中n将是s3数组的大小。

修改

附加问题:如果一个字符串大于另一个字符串,则会跳过超出公共长度的第一个字符串。这是因为您使用for (i+=1;...)启动了其他for循环,但i已指向要复制的右侧char。只需将这两个循环更改为for (;...)

即可

正如您刚才所说,如果您更喜欢指针算术,s1[i]*(s1+i)相同。顺便说一句,听起来很奇怪,它也跟i[s1]一样!

超出字符串末尾的奇怪字符可能是由于不正确的长度导致输出空终止符及其后的结果。检查read_line()以确保它返回不计算空终止符的字符串长度。但是使用调试器应该很容易解决。