是否可以在 运行 时间内将正确数量的 space 分配给 C 中的字符串?

Is it possible to allocate the correct amount of space to strings in C during run time?

有没有办法在运行时分配足够space而不询问字符串的长度?

int main() 
{
    char **tests;
    int counter;
    int i;
    int j;
    int testCases;

    scanf(" %d", &testCases);

    tests = malloc(sizeof(char *) * testCases);

    for(i = 0; i < testCases; i++)
    //stuck here, normally I would put tests[i] = malloc(length_of_string)
    //but I don't know the length of string until runtime
}

由于您使用 scanf 来读取计数,我想您也将使用它来读取字符串。如果您的 C 库与 Posix 2008 兼容 [注 1],那么您可以将 m 长度修饰符用于 scanf %s %c%[ 格式,这将导致 scanf 自动为您分配字符串。 (您需要提供字符串指针的地址——即 char**——而不仅仅是一个字符串指针。)

请注意,在 scanf 格式 " %d" 中,space 字符是多余的。 %d 格式说明符,如 %s,自动跳过前导白色 space。

这是一个例子,如果你正在阅读白色-space分隔的单词:

int n_strings;
if (scanf("%d", &n_strings) != 1) {
  /* Handle input error; do not continue */
}
/* Should check to make sure n_strings is > 0 */
char** strings = malloc(n_strings * sizeof *strings);
if (!strings) {
  /* Handle alloc error; do not continue */
}
for (int i = 0; i < n_strings; ++i) {
  if (scanf("%ms", &strings[i]) != 1) {
    /* Handle input error, do not continue */
  }
}

您更有可能希望完整阅读。在这种情况下,再次使用 Posix 2008 兼容库,您可以使用 getline 函数,它读取整行——包括换行符——并将其存储到 malloc 的存储中。与 scanf m 修饰符不同,getline 要求您为其提供地址的缓冲区指针为 NULL 或先前调用 malloc 的结果。另外,调用成功会return实际存储的字符数,可以派上用场。

以上示例使用 getline:

int n_strings;
if (scanf("%d", &n_strings) != 1) {
  /* Handle input error; do not continue */
}
/* Skip the rest of the first line */
while (getchar() != '\n') {}
char** strings = malloc(n_strings * sizeof *strings);
if (!strings) {
  /* Handle alloc error; do not continue */
}

for (char **strp = strings, **limit = strings + n_strings;
     strp < limit;
     ++strp) {
  size_t n = 0;
  *strp = NULL;
  ssize_t len = getline(strp, &n, stdin);
  if (len <= 0) {
    /* Handle input error, do not continue */
  }
  /* You probably don't want the trailing newline. But remember
   * that is is possible that it doesn't exist if the last character
   * in the file is not a newline.
   */
  if (len && (*strp)[len - 1] == '\n')
    (*strp)[len - 1] = 0;
}

  1. 据我所知,如果您使用相当现代的 Linux 或 Mac [=58=,标准 C 库将符合 Posix 2008 ] X. 这里推荐的两个功能在被纳入标准之前都在 Gnu 标准 C 库中实现。

    要启用 Posix 2008 功能,您需要将这些行中的一行(或两行)放入源代码 之前 任何系统包括:

    #define _POSIX_C_SOURCE 200809L
    #define _XOPEN_SOURCE 700
    

    如果您使用的是较旧的 glibc,其中 getlinem 标志仍被视为 Gnu 扩展,请使用此定义:

    #define _GNU_SOURCE
    

使用固定缓冲区一次读取一点点,然后重新分配内存。你不能使用 scanf。它将忽略所有空格。

#define BUFSIZE 100
#define INITIALSIZE 20

int main(int argc, char* argv[])
{


    char buf[BUFSIZE];
    char **tests;
    int counter;
    int i;
    int j;
    int testCases;

    scanf(" %d", &testCases);
    // get rid of the CR/LF
    fgets( buf, sizeof(buf), stdin );

    tests = (char **)malloc(sizeof(char *) * testCases);

    for(i = 0; i < testCases; i++) {
        int availableSpace, newSize;
        availableSpace = newSize = INITIALSIZE;
        tests[i] = (char *)malloc(availableSpace * sizeof(char));   
        tests[i][0] = '[=10=]';
        while ( fgets( buf, sizeof(buf), stdin ) != NULL )
        {

            if ( availableSpace <= (int) strlen(buf) ) {
                newSize += (int) strlen(buf) - availableSpace + 1;
                tests[i] =  (char *)realloc(tests[i], newSize * sizeof(char));
                availableSpace = 0;
            }
            else {
                availableSpace -= strlen(buf);
            }
            strcat(tests[i], buf);
            if (strlen(buf) < BUFSIZE-1) {
                break;
            }
        }
    }
}