我的程序应该读取两个字符串并以新字符串(第三个)打印为第一个字符串中的第一个字符,然后打印第二个字符串的第一个字符,然后打印第一个字符串的第二个字符的方式组合它们,依此类推。较长字符串中的任何额外字符都简单地放置在末尾。
这里是代码:
#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()
中调用它时,打印第三个字符串会导致什么也没有打印,就好像第三个字符串是空的一样!
打印方法是正确的,因为我能够很好地打印第一个和第二个字符串。我无法弄清楚我在这里做错了什么,因为每个步骤的逻辑对我来说都是有意义的。虽然我是 C 语言的新手,但指针算术对我来说仍然很令人烦恼。
编辑:
1)令我惊讶的是,编译它没有给我任何错误或警告(gcc)。
2) 将 s3 的赋值替换为 *s3 以及 *(s1 或 s2 + i) 使得该程序在大部分情况下都可以工作。尽管现在输出中的最后几个字符我得到了意想不到的结果。谢谢 Christophe,但我试图避免在此程序中使用任何数组索引。
最佳答案
哎呀!在 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()
非常不安全:该函数对数组的大小一无所知。如果 a
和 b
充满 N-1
个字符和结尾 '\0'
:该函数会将 2*N-1
个字符写入 c
,因此缓冲区溢出会损坏您的内存。致命漏洞的两个简单修复:
- 将
c
的大小更改为2*N
- 将函数签名更改为
void merge_s (char *s3, char *s1, char *s2, size_t n)
,其中 n 是s3
数组的大小。
编辑:
其他问题:如果一个字符串比另一个字符串大,您将跳过第一个超过公共(public)长度的字符。这是因为您使用 for (i+=1;...)
启动额外的 for 循环,但 i
已经指向要复制的正确字符。只需将这两个循环更改为 for (;...)
正如您刚才所说,如果您更喜欢指针算术,s1[i]
与 *(s1+i)
相同。顺便说一句,尽管听起来很奇怪,但它也与 i[s1]
相同!
超出字符串末尾的奇怪字符可能是由于长度不正确导致输出空终止符及超出范围造成的。检查 read_line() 以确保它返回的字符串长度不包括空终止符。但这应该很容易用调试器修复。
关于c - 函数不向数组分配任何内容(使用指针算术),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39949245/