读取C中未定义长度的字符串

Mar*_*les 8 c string pointers

首先(一如既往)我想对我的英语道歉,可能不够清楚.

我不擅长C编程,并且我被要求读取未定义长度的"字符串"输入.

这是我的解决方案

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

char *newChar();
char *addChar(char *, char);
char *readLine(void);

int main() {
  char *palabra;
  palabra = newChar();

  palabra = readLine();
  printf("palabra=%s\n", palabra);

  return 0;
}

char *newChar() {
  char *list = (char *) malloc(0 * sizeof (char));
  *list = '\0';
  return list;
}

char *addChar(char *lst, char num) {
  int largo = strlen(lst) + 1;
  realloc(&lst, largo * sizeof (char));
  *(lst + (largo - 1)) = num;
  *(lst + largo) = '\0';
  return lst;
}

char *readLine() {
  char c;
  char *palabra = newChar();

  c = getchar();
  while (c != '\n') {
    if (c != '\n') {
      palabra = addChar(palabra, c);
    }
    c = getchar();
  }
  return palabra;
}
Run Code Online (Sandbox Code Playgroud)

拜托,我很感激你帮助我告诉我这是一个好主意还是给我一些其他的想法(还告诉我它是否是指针的"正确"用法).

提前致谢


编辑:嗯,谢谢你的答案,他们非常有用.现在我发布了编辑(我希望更好)的代码,也许对于C新手(像我一样)有用,并再次被反馈.

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


void reChar(char **, int *);
void readLine(char **, int *);

int main() {
    char *palabra = NULL;
    int largo = 0;

    reChar(&palabra, &largo);
    readLine(&palabra, &largo);
    printf("palabra=%s\n", palabra, largo);

    system("pause");
    return 0;
}

void reChar(char **lst, int *largo) {
    (*largo) += 4;
    char *temp = (char*) realloc(*lst, (*largo) * sizeof (char));

    if (temp != NULL) {
        *lst = temp;
    } else {
        free(*lst);
        puts("error (re)allocating memory");
        exit(1);
    }
}

void readLine(char **lst, int *largo) {
    int c;
    int pos = 0;

    c = getchar();
    while (c != '\n' && c != EOF) {
        if ((pos + 1) % 4 == 0) {
            reChar(lst, largo);
        }
        (*lst)[pos] =(char) c;
        pos++;
        c = getchar();
    }
    (*lst)[pos] = '\0';
}
Run Code Online (Sandbox Code Playgroud)

PS:

  • 似乎足以减缓"palabra"的增加幅度.

  • 我不确定是否捕获getchar()到a int然后将其转换为a char是正确的方式来解决EOF陷阱

Jon*_*ler 23

  1. 查找POSIX的定义getline().

  2. 请记住,您需要从中捕获返回值realloc(); 不能保证新的存储器块与旧存储器块的起始位置相同.

  3. 知道malloc(0)可能返回一个空指针,或者它可能返回一个不可用的非空指针(因为它指向零字节的内存).

  4. *list = '\0';当列表指向已分配内存的零字节时,您可能不会写' ; 你没有在那里写的许可.如果您返回NULL,则可能会获得核心转储.在任何情况下,您都在调用未定义的行为,这是" 一个坏主意 ™".(谢谢)

  5. palabra = newChar();main()泄漏内存-假设你解决已经讨论过的其他问题.

  6. 代码中readLine()没有考虑在获取换行符之前获取EOF的可能性; 这很糟糕,当内存分配(最终)失败时会导致核心转储.

  7. 您的代码将表现出较差的性能,因为它一次分配一个字符.通常,您应该一次分配多于一个额外字符; 从初始分配大约4个字节开始,每次需要更多空间时将分配加倍可能会更好.保持初始分配较小,以便正确测试重新分配代码.

  8. 返回值getchar()是a int,而不是a char.在大多数机器上,它可以返回256个不同的正字符值(即使char是有符号类型)和单独的值EOF,它与所有char值不同.(如果机器的字节大于8位,则该标准允许它返回超过256个不同的字符.)(谢谢)C99标准§7.19.7.1说fgetc():

    如果未设置stream指向的输入流的文件结束指示符并且存在下一个字符,则fgetc函数将该字符作为转换为int的unsigned char获取,并为该流提前关联的文件位置指示符(如果定义).

    (强调补充.)它定义getchar()getc(),并且它定义getc()fgetc().

  9. (借:谢谢).第一个参数realloc()是指向当前分配的内存开头的指针,而不是指向当前分配的内存开头的指针.如果您没有从中获得编译警告,则表示您没有在编译器上设置足够的警告进行编译.您应该将警告调到最大.您应该注意编译器警告 - 它们通常表示代码中存在错误,尤其是在您仍在学习语言时.

  10. 在您知道已到达行尾(或输入结束)之前,通常更容易保持字符串不带空终止符.当没有更多要读取的字符时(暂时),然后追加null,以便在返回之前正确终止字符串.只要您跟踪字符串中的位置,这些函数就不需要字符串在读取时正确终止.但是,确保你有足够的空间将NUL添加'\0'到字符串的末尾.

有关很多相关讨论,请参阅Kernighan&Pike的"编程实践".我也认为Maguire的"编写固体代码"提供了相关的建议,因为它有点过时了.但是,你应该知道有些人会亵渎这本书.因此,我推荐TPOP而不是WSC(但亚马逊的WSC价格为0.01美元+ p&p,而TPOP起价为20.00美元+ p&p - 这可能是市场发言).


TPOP之前在 http://plan9.bell-labs.com/cm/cs/tpophttp://cm.bell-labs.com/cm/cs/tpop,但现在都是(2015-08-10)破碎.另见TPOP上的维基百科.


sth*_*sth 5

  • 您总是分配比您正在使用的字节少一个字节.例如,在开头为零字符分配空间,然后尝试将(不存在的)第一个字符设置为'\0'.

  • realloc不将指针指针作为第一个参数.它应该像这样使用:

    lst = realloc(lst, largo * sizeof (char));
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果你想处理了内存不足的状况下,你将不得不检查malloc()realloc()返回NULL.

  • 在开头分配更大的缓冲区并以更大的步骤增加缓冲区而不是分别重新分配每个添加的字符会更有效.