【问题标题】:Why does my program stop when I call a function?为什么我调用函数时程序会停止?
【发布时间】:2021-07-01 05:16:03
【问题描述】:

我正在编写一个函数,它应该反转给定的单词或输入,但是当我调用它时程序会一直停止。

代码是:

#include <stdio.h>
#define MAX 1000

void reverse(char normal[], char reversed[]);

main() {

    int c, i;
    char line[MAX], reversed_line[MAX];

    for (i=0; (c = getchar()) != EOF && c != '\n'; i++) {
        line[i] = c;
        if (c == '\n')
            i++;
    }
    line[i] = '\0';
    copy(line, reversed_line);
    printf("%s", reversed_line);

    return 0;
}


void reverse(char normal[], char reversed[]) {

    int i, len;

    for (i = 0; normal[i] != '\0'; i++)
        len++;
        
    i = 0;
    while ((reversed[len-i] = normal[i]) != '\0')
        i++;
}

程序停止的行是copy(line, reversed_line);,它给出的错误是[Error] ld returned 1 exit status

任何帮助将不胜感激

【问题讨论】:

  • 阅读n1570,见this C reference,你的C编译器的文档(例如GCC..被调用为gcc -Wall -Wextra -g)和调试器(例如GDB.. .)。如果允许,请使用Clang static analyzer
  • 您在main 中的第一个for 循环可能会触发buffer overflow。我建议改用fgets...您的错误发生在编译时,因此请阅读gcc 使用的GNU binutils 的文档。此外,MAX 应重命名(例如,MAXLINELENGTH)以提高可读性
  • 阅读Modern C并下载,然后研究GNU libc的源代码,因为它是free software。从GNU bash的源代码中获取灵感
  • 您应该查阅任何 C 教科书以了解 main 函数签名的外观。隐式int 类型和空参数列表是一个早已过去的世纪的特征。
  • @BasileStarynkevitch :研究 libc 或 bash 源代码来解决这个简单的初学者误解是一把大锤,可能会进一步混淆。我不会提出建议。

标签: c reverse c-strings function-definition


【解决方案1】:

对于这个 for 循环中的初学者

for (i=0; (c = getchar()) != EOF && c != '\n'; i++) {
    line[i] = c;
    if (c == '\n')
        i++;
}

您没有检查i 是否大于或等于MAX。而且这个if语句

    if (c == '\n')
        i++;

由于循环条件,永远不会执行。

你声明了函数reverse

void reverse(char normal[], char reversed[]);

但是您尝试调用另一个函数 copy 而不是该函数。

copy(line, reversed_line);

同样是函数reverse中的这个循环

while ((reversed[len-i] = normal[i]) != '\0')
        i++;

正在尝试将终止零字符'\0' 写入参数reversed 指向的字符数组的第一个位置。

你需要的是以下内容

#include <stdio.h>

#define MAX 1000

char * reverse_copy( const char normal[], char reversed[] );

int main(void) 
{
    char line[MAX], reversed_line[MAX];

    size_t i = 0;
    
    for  ( int c; i + 1 < MAX && ( c = getchar() ) != EOF && c != '\n'; i++ ) 
    {
        line[i] = c;
    }
    
    line[i] = '\0';
    
    puts( reverse_copy( line, reversed_line ) );
    
    return 0;
}

char * reverse_copy( const char normal[], char reversed[] ) 
{
    size_t len = 0;

    while ( normal[len]  != '\0' ) ++len;

    reversed += len;
    
    *reversed = '\0';
    
    for ( ; len != 0; --len )
    {
        *--reversed = *normal++;
    }

    return reversed;
}

如果要输入例如字符串

Hello World!

那么程序输出将是

!dlroW olleH

【讨论】:

  • 一个问题,为什么不用fgets来读取输入字符串呢?
  • @AndySukowski-Bang 至于 fgets,我试图保留问题作者使用的方法。
【解决方案2】:

您在代码中做了一些不必要的事情。例如,当您已经知道长度时,为什么在 reverse 的 while 循环中存在此条件?

while ((reversed[len - i] = normal[i]) != '\0')

我已经重写了你的整个代码来优化一些东西。也许这是对0___________'s answer 的有益补充。我在代码中包含了很多解释 cmets。

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

#define MAX 1000

void reverse(char *str, char *rev_str, size_t len)
{
    /* check if `str` is a valid string */
    if (str == NULL) {
            fprintf(stderr, "Error: invalid string\n");
            exit(EXIT_FAILURE);
    }

    /* take null character into account */
    for (int i = 0; i < len - 1; ++i)
            rev_str[len - i - 2] = str[i];
    rev_str[len - 1] = '\0';
}

int main(void)
{
    char str[MAX];
    fputs("Input: ", stdout);
    /* just use `fgets` and prevent buffer overflow */
    fgets(str, MAX, stdin);

    /* `len` includes null character */
    size_t len = strlen(str);
    /* change '\n' to '\0' */
    str[len - 1] = '\0';

    /* `sizeof(rev_str)` doesn't always need to be `MAX` */
    char rev_str[len];
    reverse(str, rev_str, len);
    printf("Output: %s\n", rev_str);

    return EXIT_SUCCESS;
}

【讨论】:

    【解决方案3】:

    首先你不执行你的程序,只尝试编译和链接它。

    错误消息表明链接失败,因为链接器没有找到函数copy,实际上从未在您的代码中定义。标准库中没有“复制”功能。如果您想复制字符串或某些内存区域,您应该使用strcpystrncpymemcpymemmove

    但是即使程序链接你的代码也有很多问题。

    这是程序的工作版本:

    #include <stdio.h>
    #define MAX 5
    
    char *reverse(char *normal, char *reversed);
    
    int main(void) {
    
        int c;
        size_t i = 0;
        char line[MAX], reversed_line[MAX];
    
        while((c = getchar()) != EOF)
        {
            line[i] = c;
            if(c != '\n') i++;
            if(i >= MAX - 1) break;
        }
        line[i] = '\0';
    
        reverse(line, reversed_line);
        printf("%s", reversed_line);
    
        return 0;
    }
    
    char *reverse(char *normal, char *reversed) 
    {
        size_t size = 0;
    
        if(normal && reversed)
        {
            while(normal[size]) size++;
            reversed[size] = 0;
            while(size)
            {
                reversed[size - 1] = *normal++;
                size--;
            }
        }
        return reversed;
    }
    

    https://godbolt.org/z/jb7b6hjfT

    【讨论】:

    • 其实strncpy可能比strcpy更可取
    • @BasileStarynkevitch 同样糟糕,甚至可能更糟。 strncpy 是程序员的陷阱。
    • 如果strncpysizeof(buf)-1 一起使用并以memset(buf, 0, sizeof(buf)) 开头,则不会
    • @BasileStarynkevitch 那么这是一个效率极低的函数。应该这样做:godbolt.org/z/oa9obM4oY
    猜你喜欢
    • 1970-01-01
    • 2017-04-12
    • 2015-12-13
    • 1970-01-01
    • 2021-01-09
    • 2013-10-17
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多