【问题标题】:failing to execute without arguments, input not parsed correctly没有参数无法执行,输入未正确解析
【发布时间】:2021-02-07 20:59:09
【问题描述】:

在下面的函数中,我试图从标准输入读取几个句子,并在用户按两次输入后处理它们。如图所示,我将内存动态分配给整个缓冲区(行集)。我遇到了:

zsh: illegal hardware instruction  ./myfunc

最小编译sn-p:

void myfunc(void) {

    int textsize = BUF_SIZE;
    char **lines = (char **) malloc(sizeof(char *) * textsize);
    int linecount = 0;
    char text[BUF_SIZE];

    while ((strcpy(text, fgets(text, BUF_SIZE, stdin))) != NULL) {
        if (text[0] == '\n') {
            break;
        }
        lines[linecount] = (char *) malloc(sizeof(char *) * strlen(text));
        strcpy(lines[linecount], text);
        linecount++;
    }
    for (int index = linecount - 1; index >= 0; --index) {
        fprintf(stdout, "%s", lines[index]);
        /* if line has newline stripped, else printf("%s", lines[index]);*/
    }

    free(*lines);
    exit(0);
}

【问题讨论】:

  • strcpy(text, fgets(text, BUF_SIZE, stdin))fgets 返回NULL 时,你认为会发生什么?
  • malloc(sizeof(char *) * strlen(text)); 应该是 malloc(sizeof(char) * (strlen(text)+1)); 因为 C 中的字符串有一个额外的字节用于终止 NUL 字符。 sizeof 的类型错误,会导致缓冲区过大,但应更改以确保正确性。
  • OT: exit(0); 这在技术上没有错,但通常不是一件好事。函数应该很少导致整个程序退出(一个常见的例外是遇到致命错误)。
  • @kaylum 感谢您的意见! a) 当 fgets 收到 NULL 时,这是否意味着标准输入仅收到两个返回键的 scnario? b)我合并了+1,但不遵循“sizeof 的类型错误”部分。说 BUF_SIZE 是 512,这意味着 512 个指针分别指向每个句子,不是吗? c) 注明。我将其替换为 return 0
  • 关于:最小编译sn-p:贴出的代码无法编译!它缺少以下语句:#include <stdio.h#include <stdlib.h>#include <string.h.

标签: c loops for-loop dynamic-memory-allocation c-strings


【解决方案1】:

在本次内存分配中使用 textsize 的值

char **lines = (char **) malloc(sizeof(char *) * textsize);

没有意义。

在while循环的条件下使用strcpy

while ((strcpy(text, fgets(text, BUF_SIZE, stdin))) != NULL) {

也没有意义,因为 1) fgets 可以返回 NULL 2) 如果 fgets 没有返回 NULL 那么它已经用字符串填充了数组文本。

所以循环至少应该写成这样

while ( fgets(text, BUF_SIZE, stdin) != NULL) {

在此声明中

lines[linecount] = (char *) malloc(sizeof(char *) * strlen(text));

您需要分配char 类型的对象数组,而不是char * 类型,并且分配的元素数量应等于tp strlen( text ) + 1

这个电话

free(*lines);

仅释放指针lines 指向的第一个分配的元素,但您需要释放所有已分配的内存。

而这个调用在函数的最后

exit(0);

再次没有任何意义。至少你可以写

return;

或者只是删除exit的调用。

该函数可以如下面的演示程序所示。

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

#define BUF_SIZE    100

void myfunc( void ) 
{
    char **lines = NULL;
    size_t linecount = 0;
    
    char text[BUF_SIZE];
    int success = 1;

    while ( success && fgets( text, BUF_SIZE, stdin ) != NULL && text[0] != '\n' ) 
    {
        char **tmp = realloc( lines, ( linecount + 1 ) * sizeof( char * ) );
        success = tmp != NULL;
        
        if ( success )
        {
            lines = tmp;
            lines[linecount] = malloc( ( strlen( text ) + 1 ) * sizeof( char ) );
            
            success = lines[linecount] != NULL;
            
            if ( success )
            {
                strcpy( lines[linecount], text );
                ++linecount;
            }
        }
    }
    
    if ( !success ) fputs( "Nor all input records were successfully stored\n", stdout );
    
    for ( size_t i = linecount; i != 0; ) 
    {
        fprintf( stdout, "%s", lines[--i]);
    }

    for ( size_t i = 0; i < linecount; ++i )
    {
        free( lines[i] );
    }
    free( lines );
}

int main(void) 
{
    myfunc();
    
    return 0;
}

如果要输入字符串

Hello
World 

那么输出将是

World 
Hello

【讨论】:

  • 这是我的理解,请纠正我: 1. fgets 100 个字符从标准输入,虽然它不是 '\n' 或返回键,你进一步处理。 2.你创建一个指向另一个你分配1字节的指针的指针? ( linecount + 1 ) * sizeof( char * ) 是一个小缓冲区,不是吗? 3. 分配后,将内存分配给 lines[ ] 中的第一个指针。它的大小由静态数组“文本”中读取的内容决定。但是如果 fgets 读取 500 个字符而 BUF_SIZE 只有 100 个呢? 4. 当内存分配成功时,你将读取的行复制到 lines[i] 中。我得到了剩下的。
  • @ankitrana_line 指向一个动态分配的指针数组。然后读取一个新字符串,您需要为另一个指针重新分配数组,该指针将指向给定字符串的动态分配数组,因此此表达式 ( linecount + 1 ) * sizeof( char * ) 指定重新分配数组的大小.如果您输入一个包含 500 个字符的字符串,则循环将迭代两次,因为 fgets 将读取该字符串作为两个字符串。
  • 有道理。谢谢!我想知道是否有办法在不创建双指针的情况下做到这一点?使用 malloc 但充其量使用 char *。有什么缺点吗?
  • @ankitrana_ 您可以声明一个具有足够数量元素的二维数组。但是这种方法可能效率低下,因为要么分配太多内存,要么用户可以输入比数组大小更多的字符串。
  • 我在想更多关于这个。你认为不使用 fgets(),也许使用 getline() 从标准输入读取会更简单?
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 2013-11-01
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多