【问题标题】:Output not as expected输出不如预期
【发布时间】:2017-02-24 00:08:40
【问题描述】:

我应该编写一个程序来提取以www. 开头并以.edu 结尾的网址。该程序显示包含在用户输入的输入中的 Web 地址。如果输入不包含以www. 开头并以.edu 结尾的网址,则程序应显示一条消息,指示找不到此类网址。

Input: http://www.usf.edu/admission
Output: www.usf.edu
Input: https://www.facebook.com/
Output: Web address starting with www. and ending with .edu not found

但是,当我的程序运行时,它没有显示正确的输出。我没有任何编译器错误或警告,所以我不确定问题可能出在哪里。

// This program extracts the text from the website URL
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define STR_LEN 1000

void read_line(char *str, int n);
void pass_check(char *str);
void extract(char *s1, char *s2);

int main(void)
{
    char instr[STR_LEN + 1];
    char outstr[STR_LEN + 1];

    printf("Please enter a URL: ");
    read_line(instr, STR_LEN);
    extract(instr, outstr);

    puts(outstr);
    pass_check(outstr);

    return 0;
}

void extract(char *s1, char *s2) {
    char *p, *q;
    q = s2;
    for (p = s1 + 7; *p != 0; p++) {
        if (*p == '/')
            break;
        else {
            *q = *p;
            q++;
        }
    }
    *q = '\0';
    *p = '\0';
}

void read_line(char *str, int n) {
    int ch;
    int i = 0;
    while ((ch = getchar()) != '\n') {
        if (i < n) {
            *str++ = ch;
            i++;
        }
    }
    *str = '\0';
}

void pass_check(char *str) {
    const char *fref = "www";
    const char *lref = "edu";

    int len = strlen(str);
    printf("%d", len);

    char *l = &str[len - 3];
    char f[STR_LEN + 1];

    strncpy(f, str, 3);

    if ((strcmp(f, fref) == 0) && strcmp(l, lref) == 0) {
        printf("Output: ");
        puts(str);
        printf("\n");
    } else
        printf("Please only insert a .edu URL.");
}

【问题讨论】:

  • 如果用户键入一个短名称——例如www.edu——你在for (p = s1+ 7;的代码会跳到字符串的末尾。甚至更短,并且您正在读取未初始化的数据(或者,至少,不一定是初始化的数据)。这很糟糕!
  • 当你得到错误的输出时,你给出了什么输入?你得到什么输出?你应该得到什么?为什么? (不管它有什么价值,它在我严格的默认编译选项下编译干净 [干得好!],并且运行并或多或少地做了我期望它做的事情。测试 - 非常随意 -在运行 macOS Sierra 10.12.3 和 GCC 6.3.0 的 Mac 上。)它可以在打印消息的末尾使用一些换行符。
  • 删除puts(outstr); 和这个printf("%d", len); 以获得您想要的输出,如图所示,没有所有这些长度,没有换行输出。最好还是让我们知道您的预期结果是什么
  • 如果我尝试示例输出 usf.edu/admission,它将打印 www.usf.edu。但是,它不会打印出“Output:”行,它还会打印出 else 语句“请仅插入 .edu URL。”
  • 嗯...前导空格会混淆它。 ftp:// URL 也是如此(部分原因是 s1+7 问题)。端口号会混淆它。 gopher://www.email.edu/ URL 混淆了它。您需要更仔细地考虑检测起点。

标签: c string pointers for-loop output


【解决方案1】:

函数strncpy() 并没有像你认为的那样做:strncpy(f, str, 3); 不会将空字节附加到f,所以strcmp(f, fref); 实际上会有未定义的行为,因为f 在前3 个之后未初始化字节。

不要使用此功能,从这些博客中了解原因:

另请注意,如果文件为空或未由换行符终止,您的 readline() 函数将运行无限循环。

这是一个更正的版本:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define STR_LEN 1000

void read_line(char *str, size_t n);
int extract(const char *str, char *dest);

int main(void) {
    char instr[STR_LEN + 1];
    char outstr[STR_LEN + 1];

    printf("Please enter a URL: ");
    read_line(instr, sizeof(instr));
    if (extract(instr, outstr)) {
        puts(outstr);
    } else {
        printf("Web address starting with www. and ending with .edu not found\n");
    }
    return 0;
}

int read_line(char *str, size size) {
    int ch;
    size_t i = 0;
    while ((ch = getchar()) != EOF && c != '\n') {
        if (i + 1 < size) {
            str[i++] = ch;
        }
    }
    str[i] = '\0';
    return (ch == EOF && i == 0) ? EOF : i;
}

int extact(const char *str, char *dest) {
    const char *p;

    *dest = '\0';

    for (;;) {
        if ((p = strstr(str, "https://www.")) != NULL) {
            p += 8;  // skip the https:// prefix
        } else 
        if ((p = strstr(str, "http://www.")) != NULL) {
            p += 7;  // skip the http:// prefix
        } else {
            break;
        }
        // URL starts with www.
        size_t len = strcspn(p, "/ \n");  // compute length of website name
        if (len > 8 && !memcmp(p + len - 4, ".edu", 4)) {
            // copy website name, assuming dest is at least as large as str
            strncat(dest, p, len);
            return 1;
        }
        str = p + len;
    }
    return 0;
}

【讨论】:

  • @Bob__:绝对。在将语义从最大字符数转换为目标大小时,我错过了这个n。谢谢。
猜你喜欢
  • 2019-08-28
  • 2021-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
相关资源
最近更新 更多