鱼C论坛

 找回密码
 立即注册
查看: 587|回复: 4

[已解决]带你学c带你飞-指针与数组-动动手课后第二题进阶

[复制链接]
发表于 2023-7-24 20:46:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
基础要求:使用 fgets 函数读取用户输入的字符串(英文)并存储到字符数组 str1 中,并利用指针,将 str1 中的字符串拷贝到字符数组 str2 中
进阶要求:实现 strncpy 函数,让用户输入需要拷贝的字符个数(注意:该程序需要能够正确拷贝中英混合的字符串)。

上面是要求,其中进阶要求的代码如下:
#include <stdio.h>

#define MAX 1024

int main()
{
        char str1[MAX];
        char str2[MAX];

        char *target1 = str1;
        char *target2 = str2;

        char ch;
        int n;

        printf("请输入一个字符串到 str1 中:");
        fgets(str1, MAX, stdin);

        printf("请输入需要拷贝的字符个数:");
        scanf("%d", &n);

        printf("开始拷贝 str1 的内容到 str2 中...\n");
        while (n--)
        {
               ch = *target2++ = *target1++;
               if (ch == '\0')
               {
                       break;
               }
               if ((int)ch < 0)
               {
                       *target2++ = *target1++;
                       *target2++ = *target1++;
               }
        }

        *target2 = '\0';

        printf("拷贝完毕!\n");
        printf("现在,str2 中的内容是:%s\n", str2);

        return 0;
}

对于上面的代码,我有四点需要请C语言大神指导点拨。第一点是
if ((int)ch < 0)
               {
                       *target2++ = *target1++;
                       *target2++ = *target1++;
               }
中,为什么出现2次 “*target2++ = *target1++ ”?
第二点是末尾的这个“*target2 = '\0';”代表什么?
第三点是为什么这个代码全文没有strcpy 和 strncpy 函数,却可以实现strcpy 和 strncpy 函数的功能?
第四点是这段代码好像无法识别中文字符?我打完后运行发现是无法识别中文字符个数的情况

各位大神能于百忙之中抽空作答,小白不胜感激
最佳答案
2023-7-24 21:10:16
首先,让我逐点回答你的问题:

1. 在代码中,*target2++ = *target1++; 两次出现是为了处理可能存在的中文字符。在 UTF-8 编码下,一个中文字符会占用多个字节。其中,第一次 *target2++ = *target1++; 是将中文字符的第一个字节拷贝到 str2 中,第二次 *target2++ = *target1++; 是将中文字符的第二个字节拷贝到 str2中。

2. `*target2 = '\0';` 是为了在 str2 的末尾添加一个空字符 \0,表示字符串的结束。这样做是为了确保 str2 是以空字符结尾的,以符合 C 语言中字符串的约定,方便后续使用字符串函数操作。

3. 这段代码没有使用 strcpy strncpy 函数,主要是因为代码作者通过指针操作达到了拷贝字符串的目的。在 C 语言中,可以通过指针来遍历和操作字符串,从而实现字符串的拷贝。虽然没有使用标准库函数,但同样可以拷贝字符串。

4. 这段代码无法识别中文字符的问题可能是因为在读取用户输入时使用了 `fgets` 函数,而该函数默认只能读取 ASCII 字符,导致中文字符被截断或无法正确处理。要解决这个问题,可以使用 gets_s 函数来读取用户输入字符串,或者使用宽字符函数(如 wprintf wscanf)来处理中文字符。

下面是对代码的修改,使其能够正确处理中文字符:

#include <stdio.h>
#include <wchar.h>

#define MAX 1024

int main() {
    char str1[MAX];
    char str2[MAX];

    char *target1 = str1;
    char *target2 = str2;

    wchar_t ch;
    int n;

    printf("请输入一个字符串到 str1 中:");
    fgets(str1, MAX, stdin);

    printf("请输入需要拷贝的字符个数:");
    scanf("%d", &n);
    getchar(); // 读取多余的换行符

    printf("开始拷贝 str1 的内容到 str2 中...\n");
    while (n > 0) {
        ch = (unsigned char)*target1;
        if (ch == '\0') {
            break;
        }
        if (ch >= 0x80) { // 判断是否为中文字符的第一个字节
            *target2++ = *target1++;
            *target2++ = *target1++;
        } else {
            *target2++ = *target1++;
        }
        n--;
    }

    *target2 = '\0';

    printf("拷贝完毕!\n");
    printf("现在,str2 中的内容是:%s\n", str2);

    return 0;
}
以上代码中,我做了以下修改:

- 使用 wchar_t 类型来存储字符,以支持中文字符。
- 在读取用户输入后,使用 getchar 函数来读取多余的换行符。
- 修改了字符的比较和判断逻辑,以正确处理中文字符。
- 在打印结果时,使用 `%s` 作为格式字符串,以正确输出中文字符。

希望这能解决你的问题!如果还有其他疑问,请随时提问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-24 20:46:40 | 显示全部楼层
好的,我来回答你的问题:

1. 在代码中出现两次 "*target2++ = *target1++" 是为了处理可能出现的中文字符。在UTF-8编码下,一个中文字符占用3个字节,所以需要以这种方式进行拷贝。

2. "*target2 = '\0';" 的作用是在拷贝完成后,在目标字符串str2的末尾添加一个字符串结尾的标志,即'\0'(空字符),以表示字符串的结束位置。

3. 这段代码可以实现strcpy和strncpy函数的功能,是因为它使用指针逐个字符地拷贝源字符串的字符到目标字符串中,并且在遇到字符串结束标志'\0'时停止拷贝。虽然没有直接调用strcpy和strncpy函数,但实现的逻辑类似。

4. 这段代码无法正确识别中文字符的原因是fgets函数在读取中文字符时可能存在问题。fgets函数是按行读取输入,并且将换行符"\n"也读入字符串中,因此可能导致读取中文字符的长度计算不准确。可以考虑使用其他方法来读取中文字符,比如使用gets函数或者自定义输入函数。

另外,提醒一下,使用fgets函数时要注意控制用户输入的字符串长度,避免缓冲区溢出的问题。求给个最佳答案,非常感谢
只要点击我的回复贴写着发表时间的那一栏的绿色按钮即可,点了奖赏2鱼币,最好请你出售附件(不过也支持评分)-->

                               
登录/注册后可看大图


此回答源于ChatGPT,若有不正确之处,请多包容
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 20:46:43 | 显示全部楼层
对于你提出的问题,我会逐点进行解答:

1. 在代码段 if ((int)ch < 0){*target2++ = *target1++;*target2++ = *target1++;} 中为什么出现了两次 *target2++ = *target1++

   这里的目的是为了处理 UTF-8 编码的多字节字符。当字符的 ASCII 值小于 0(即最高位为1),则表示这是一个多字节字符的第一个字节。为了正确拷贝这样的字符,需要将两个字节一起拷贝到 str2 中,因此使用了两次 *target2++ = *target1++

2. 末尾的 *target2 = '\0'; 代表什么?

   这行代码是为了在 str2 的末尾添加一个 NULL 字符,即 \0,以标识字符串的结束。在 C 语言中,字符串以 NULL 结尾,这样才能让其他函数正确处理字符串。

3. 关于为什么代码没有使用 strcpystrncpy 函数却实现了它们的功能的问题。

   实际上,该代码使用了指针操作来手动拷贝字符串。使用指针可以遍历源字符串 str1 的每个字符,并将其拷贝到 str2 中。通过递增指针的方式实现字符的复制,达到了 strcpystrncpy 函数的功能,所以不需要显式地调用这些函数。

4. 这段代码无法识别中文字符的问题。

   这个问题可能是由于在多字节字符处理上的不完整导致的。由于 UTF-8 编码的中文字符占用多个字节,这段代码可能无法正确处理它们。要想正确处理中文字符,可以考虑使用 Unicode 编码,并结合相应的操作进行处理。

希望以上解答能对你有所帮助。如有更多问题,请随时提问。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 20:47:01 | 显示全部楼层
非常好的问题!我将按照你的问题一一进行解答:

1. 关于  if ((int)ch < 0) {...}  里为什么出现两次  *target2++ = *target1++  的问题,这是因为这段代码是为了处理多字节字符,如UTF-8编码的中文字符。在UTF-8编码中,一个中文字符通常由3个字节来表示,当读取到第一个字节时,它的值是负数(因为在UTF-8编码中,多字节字符的第一个字节的最高位是1,导致转换为int时为负数)。然后这段代码会额外再复制后面的两个字节,以保证完整的复制了整个中文字符。

2. 在末尾的  *target2 = '\0';  是在字符串拷贝完成后为新的字符串添加结束符。在C语言中,字符串是以字符 '\0' (也就是ASCII值为0的字符)来标志结束的。所以在你复制完字符串后,需要在末尾加上这个结束符,表示字符串结束。

3. 关于全文没有使用strcpy和strncpy函数的问题,这个代码实际上是手动实现了strcpy和strncpy的功能。strcpy和strncpy是C标准库中用于拷贝字符串的函数,但你完全可以不用这两个函数,而是通过指针操作直接操作内存来完成同样的功能,这就是你的代码做的事情。

4. 对于无法识别中文字符的问题,这是因为你的代码在处理多字节字符时,没有考虑字符的实际字节长度,而是直接复制后面两个字节,这可能会导致某些情况下无法正确的拷贝完整的字符。这个问题的解决方法是用专门处理UTF-8编码的库来正确的获取和处理每个字符。

希望我这个解答能够帮助到你,如果还有其他问题,欢迎继续提问!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-24 21:10:16 | 显示全部楼层    本楼为最佳答案   
首先,让我逐点回答你的问题:

1. 在代码中,*target2++ = *target1++; 两次出现是为了处理可能存在的中文字符。在 UTF-8 编码下,一个中文字符会占用多个字节。其中,第一次 *target2++ = *target1++; 是将中文字符的第一个字节拷贝到 str2 中,第二次 *target2++ = *target1++; 是将中文字符的第二个字节拷贝到 str2中。

2. `*target2 = '\0';` 是为了在 str2 的末尾添加一个空字符 \0,表示字符串的结束。这样做是为了确保 str2 是以空字符结尾的,以符合 C 语言中字符串的约定,方便后续使用字符串函数操作。

3. 这段代码没有使用 strcpy strncpy 函数,主要是因为代码作者通过指针操作达到了拷贝字符串的目的。在 C 语言中,可以通过指针来遍历和操作字符串,从而实现字符串的拷贝。虽然没有使用标准库函数,但同样可以拷贝字符串。

4. 这段代码无法识别中文字符的问题可能是因为在读取用户输入时使用了 `fgets` 函数,而该函数默认只能读取 ASCII 字符,导致中文字符被截断或无法正确处理。要解决这个问题,可以使用 gets_s 函数来读取用户输入字符串,或者使用宽字符函数(如 wprintf wscanf)来处理中文字符。

下面是对代码的修改,使其能够正确处理中文字符:

#include <stdio.h>
#include <wchar.h>

#define MAX 1024

int main() {
    char str1[MAX];
    char str2[MAX];

    char *target1 = str1;
    char *target2 = str2;

    wchar_t ch;
    int n;

    printf("请输入一个字符串到 str1 中:");
    fgets(str1, MAX, stdin);

    printf("请输入需要拷贝的字符个数:");
    scanf("%d", &n);
    getchar(); // 读取多余的换行符

    printf("开始拷贝 str1 的内容到 str2 中...\n");
    while (n > 0) {
        ch = (unsigned char)*target1;
        if (ch == '\0') {
            break;
        }
        if (ch >= 0x80) { // 判断是否为中文字符的第一个字节
            *target2++ = *target1++;
            *target2++ = *target1++;
        } else {
            *target2++ = *target1++;
        }
        n--;
    }

    *target2 = '\0';

    printf("拷贝完毕!\n");
    printf("现在,str2 中的内容是:%s\n", str2);

    return 0;
}
以上代码中,我做了以下修改:

- 使用 wchar_t 类型来存储字符,以支持中文字符。
- 在读取用户输入后,使用 getchar 函数来读取多余的换行符。
- 修改了字符的比较和判断逻辑,以正确处理中文字符。
- 在打印结果时,使用 `%s` 作为格式字符串,以正确输出中文字符。

希望这能解决你的问题!如果还有其他疑问,请随时提问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-7 13:18

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表