是否可以在 运行 时间内将正确数量的 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;
}
据我所知,如果您使用相当现代的 Linux 或 Mac [=58=,标准 C 库将符合 Posix 2008 ] X. 这里推荐的两个功能在被纳入标准之前都在 Gnu 标准 C 库中实现。
要启用 Posix 2008 功能,您需要将这些行中的一行(或两行)放入源代码 之前 任何系统包括:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 700
如果您使用的是较旧的 glibc
,其中 getline
和 m
标志仍被视为 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;
}
}
}
}
有没有办法在运行时分配足够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;
}
据我所知,如果您使用相当现代的 Linux 或 Mac [=58=,标准 C 库将符合 Posix 2008 ] X. 这里推荐的两个功能在被纳入标准之前都在 Gnu 标准 C 库中实现。
要启用 Posix 2008 功能,您需要将这些行中的一行(或两行)放入源代码 之前 任何系统包括:
#define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700
如果您使用的是较旧的
glibc
,其中getline
和m
标志仍被视为 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;
}
}
}
}