返回使用从输入读取的行创建的字符串

时间:2015-11-25 23:29:53

标签: c string pointers input

我正在尝试编写一个C 函数,该函数返回从输入读取的行作为char * 。我在Windows上,我在命令行中测试我的程序,给出文件作为我的程序的输入和输出,如下所示:

cl program.c
program < test_in.txt > test_out.txt

这是我的(不工作)功能:

char* getLine(void)
{
    char* result = "";
    int i, c;

    i = 1;
    while((c = getchar()) != EOF)
    {
         *result++ = c;
         i++;

         if(c == '\n')
            return result - i;
    }

    return result - i;
}

我期待它能够发挥作用,因为我之前写过:

char* getString(char* string)
{

    //char* result = string; // the following code achieve this.
    char* result = "";
    int i;

    for(i = 1; *result++ = *string++; i++);

    return result - i;
}

这些代码行具有正确的行为。

即使每个答案都会受到赞赏,我也会非常感激 如果有人能解释我为什么我的getString()函数在我的getLine()函数不时有效。

4 个答案:

答案 0 :(得分:3)

由于您正在修改字符串文字,因此这两个函数都有undefined behaviour。它只是似乎在一个案例中工作。基本上,result需要指向可以合法访问的内存,而在任何一个代码段中都不是这样。

在同一主题上,您可能会发现这很有用:What Every C Programmer Should Know About Undefined Behavior

答案 1 :(得分:3)

您的函数没有为正在读取的字符串分配足够的空间。变量char * result =“”定义了一个指向字符串文字的字符串(“”,空字符串),并将一些任意数量的字符存储到result指向的位置。

char* getLine(void)
{
    char* result = ""; //you need space to store input
    int i, c;

    i = 1;
    while((c = getchar()) != EOF)
    {
        *result++ = c; //you should check space
        i++;

        if(c == '\n')
            return result - i; //you should null-terminate
    }
    return result - i; //you should null-terminate
}

你需要为你的字符串分配空间,这很有挑战性,因为你不知道你需要多少空间先验。因此,您需要决定是否限制读取的数量(ala fgets),或者在阅读更多内容时动态重新分配空间。另外,如何表明您已完成输入(达到EOF)?

以下备选方案假定动态重新分配是您选择的策略。

char* getLine(void)
{
    int ch; int size=100; size_t pos=0;
    char* result = malloc(size*sizeof(char*));
    while( (ch=getchar()) != EOF )
    {
        *result++ = ch;
        if( ++pos >= size ) {
            realloc(result,size+=100);
            //or,realloc(result,size*=2);
            if(!result) exit(1); //realloc failed
        }
        if( c=='\n' ) break;
    }
    *result = '\0'; //null-terminate
    return result - pos;
}

完成上述函数返回的字符串后,请记得释放()分配的空格。

此替代方案假设您提供一个缓冲区来存储字符串(并指定缓冲区的大小)。

char* getLine(char* buffer, size_t size)
{
    int ch;
    char* result = buffer;
    size_t pos=0;
    while( (ch=getchar()) != EOF )
    {
        *result++ = ch;
        if( ++pos >= size ) break; //full
        if( c=='\n' ) break;
    }
    *result = '\0'; //null-terminate
    return buffer;
}

两者都避免了检测EOF和有足够空间存储字符读取之间的微妙交互。解决方案是在读取并且没有足够空间时缓冲字符,然后在随后的读取中注入该字符。您还需要null-ter

答案 2 :(得分:1)

这样想。 当你说

char* result = "";

您正在设置指针'result'以指向1字节的空终止字符串(只是null)。由于它是局部变量,因此将在堆栈中分配。

然后当你说

*result++ = c;

您将该值'c'存储到该地址+ 1 那么,你把它放在哪里? 好吧,大多数堆栈都是向下的;所以他们向低地址发展;所以,你可能正在写堆栈上已经存在的东西(任何调用它的返回地址,它需要恢复的所有寄存器以及各种重要的东西)。

这就是为什么你必须非常小心指针。

答案 3 :(得分:1)

当您希望从函数返回一个字符串时,您有两个选项(1)为函数提供一个字符串,并有足够的空间来保存字符串(包括空终止字符),或者(2)动态分配内存对于函数内的字符串并返回一个指针。在你的功能中,你还必须有一种方法来确保你没有写出超出可用空间的末尾你为空终止字符留出空间。如果要向函数提供数组,并且保持读取字符的数量,则需要传递最大大小。

将它们放在一起,你可以做类似的事情:

#include <stdio.h>

#define MAXC 256

char* getLine (char *s, int max)
{
    int i = 0, c = 0;
    char *p = s;

    while (i + 1 < max && (c = getchar()) != '\n' && c != EOF) {
        *p++ = c;
        i++;
    }
    *p = 0;
    return s;
}

int main (void) {

    char buf[MAXC] = {0};

    printf ("\ninput : ");
    getLine (buf, MAXC);

    printf ("output: %s\n\n", buf);

    return 0;
}

示例/输出

$ ./bin/getLine

input : A quick brown fox jumps over the lazy dog.
output: A quick brown fox jumps over the lazy dog.