C 如何输入n行字符串,每行包含m个字符,其中可能包含空格作为字符?
这是我的代码,它试图获取行数(n)和C 如何输入n行字符串,每行包含m个字符,其中可能包含空格作为字符?,c,pointers,C,Pointers,这是我的代码,它试图获取行数(n)和 每行中的字符(m)作为输入。但在运行时需要n和m 之后不接受任何输入。预期输入也可能包含空格 #include<stdio.h> int main() { int n,m,i,j; scanf("%d%d",&n,&m); char **a=(char**)malloc(n); for(i=0;i<m;i++) a[i]=(char*)malloc(m+1); for(
每行中的字符(m)作为输入。但在运行时需要n和m 之后不接受任何输入。预期输入也可能包含空格
#include<stdio.h>
int main()
{
int n,m,i,j;
scanf("%d%d",&n,&m);
char **a=(char**)malloc(n);
for(i=0;i<m;i++)
a[i]=(char*)malloc(m+1);
for(i=0;i<n;i++)
scanf("%[^\n]%*c", a[i]);
}
/*An example of input would be:
4 4
####
#S #
## #
#E #
*/
#包括
int main()
{
int n,m,i,j;
scanf(“%d%d”,&n,&m);
字符**a=(字符**)malloc(n);
对于(i=0;i
// scanf("%d%d",&n,&m); change to
scanf("%d %d%*c",&n,&m); // better suggestion
考虑到输入格式,这是必要的
及
而且,由于某种原因,m和in-bellow循环是混合的
for(i=0;i<m;i++)
a[i]=(char*)malloc(m+1);
for(i=0;i<n;i++)
scanf("%[^\n]%*c", a[i]);
for(i=0;i您会问“但是我的代码在处理输入时有什么问题?”在评论中。这是一个公平的问题。您在回答问题时收到的建议是,根据经验,如何避免尝试使用scanf
进行面向行的输入的陷阱。底线是,除非您有非常确定和有保证的输入,否则使用scanf
进行面向行的输入是我们的选择为什么?因为输入的任何变化都可能导致与scanf
的匹配失败,使用其他工具不会有问题
这是否意味着scanf
不好,不应该使用?当然不是,这意味着对于面向行的输入,更好的选择通常是面向行的libc函数,如fgets
或getline
。甚至是面向字符的函数,如getchar()
或fgetc
可以提供大量灵活的输入处理。也就是说,scanf
确实有它的位置,但和其他东西一样,它也有它的优点和缺点。只需根据工作需要来权衡它们
关于你的代码。怎么了?评论中指出了很多小问题。最大的是char**a=(char**)malloc(n);
。你只分配n
字节的存储空间,而不是n
指针。每个指针是4
或8
字节(通常为32/64位框)。因此您的分配至少需要:
char **a = malloc (n * sizeof *a); /* don't cast the return */
下一期,您将尝试在for
循环中填充行。虽然您可能已收到一些n
,但无法保证您将实际有那么多行数据要读取。如果您没有,则您将强制代码读取并为不存在的输入分配。While
循环可能适合一点我觉得这里更好
分配内存时,需要保留一个指向每次分配开始的指针,以便在不再需要时释放内存。只要养成跟踪分配的内存并在使用完后释放内存的习惯。当退出时释放内存,当您开始编写分配内存的函数时,代码将泄漏l如果你没有妥善管理它的习惯,那就好比一个筛子
现在,需要注意的是,我们都知道使用fgets
或getline
是首选方法,并且以换行符开始的行将是一个问题,您可以编写代码来使用scanf
并手动为字符串分配存储空间,这种合理的方式只需添加一些内容即可您的原始代码。请看一看,如果您有问题,请告诉我
#include <stdio.h>
#include <stdlib.h>
/* validate memory allocation succeeded */
void checkalloc (void *p)
{
if (!p) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
}
/* empty any characters remaining in input buffer */
void emptyinputbuffer (FILE *fp)
{
int c;
while ((c = fgetc(fp)) != '\n' && c != EOF) {}
}
int main (void)
{
int n, m, i;
n = m = i = 0; /* always initialize your variables */
if (scanf ("%d%d",&n,&m) != 2) { /* scanf has a return -- use it */
fprintf (stderr, "error: failed to read 'm' & 'n'\n.");
exit (EXIT_FAILURE);
}
emptyinputbuffer (stdin); /* remove trailing newline from input buffer */
char **a = malloc (n * sizeof *a); /* you need sizeof to allocate 8 bytes */
checkalloc (a); /* always validate every allocation */
/* allocate storage for first string and validate */
a[i] = malloc (sizeof **a * (m + 1)); /* you could omit sizeof here, =1 */
checkalloc (a[i]);
while (scanf("%[^\n]%*c", a[i]) == 1) /* while instead, lines maybe less */
{
if (++i == n) break;
a[i] = malloc (sizeof **a * (m + 1));
checkalloc (a[i]);
}
if (i < n) n = i; /* save the number of lines actually read */
for (i = 0; i < n; i++) /* print them out */
printf (" line[%2d] : %s\n", i, a[i]);
for (i = 0; i < n; i++) /* free allocated memory */
free (a[i]);
free (a);
return 0;
}
编译
gcc -Wall -Wextra -o bin/scanf_loop scanf_loop.c
输出
$ printf "4 4\n####\n#5 #\n## #\n#E #\n"
4 4
####
#5 #
## #
#E #
$ printf "4 4\n####\n#5 #\n## #\n#E #\n" | ./bin/scanf_loop
line[ 0] : ####
line[ 1] : #5 #
line[ 2] : ## #
line[ 3] : #E #
内存使用检查
$ printf "4 4\n####\n#5 #\n## #\n#E #\n" | valgrind ./bin/scanf_loop
==11065== Memcheck, a memory error detector
==11065== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==11065== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==11065== Command: ./bin/scanf_loop
==11065==
line[ 0] : ####
line[ 1] : #5 #
line[ 2] : ## #
line[ 3] : #E #
==11065==
==11065== HEAP SUMMARY:
==11065== in use at exit: 0 bytes in 0 blocks
==11065== total heap usage: 5 allocs, 5 frees, 52 bytes allocated
==11065==
==11065== All heap blocks were freed -- no leaks are possible
==11065==
==11065== For counts of detected and suppressed errors, rerun with: -v
==11065== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
在调试器中运行它,逐行查看程序正在执行的操作。无需如此快速地转向Stackoverflow。scanf(“%[^\n]%*c”,a[i]);
如果该行以'\n'
开头,则会失败。只需使用fgets()读取该行即可<代码>,然后处理数据。张贴的代码是C,不是C++,请删除C++标签,你有<代码> C <代码>和<代码> C++ >代码>标签,但是这看起来是C代码。你在找什么?1)不要从MalCube()中返回返回的值。因为返回值的类型是void*
,可以分配给任何指针,所以它会造成维护上的麻烦,不需要。2)始终检查(!=NULL)返回值以确保操作成功。还需要处理scanf(“%d%d”、&n、&m)中的剩余\n
)推荐fgets()/sscanf()
2)也a[i]=malloc(m+2);fgets(a[i],m+2,stdin);
for\n\0
@chux刚刚注意到部分感谢您的建议,最好使用scanf(“%d%d%*c”、&n,&m)
而不是scanf
但是我的代码在处理输入时有什么问题?而不是a[strlen(a[i])-1]=‘0’,,谢谢你,戴维,我真的很感激你的努力!你把我带到了很深的地方,我知道我犯了什么错误,遵循什么规则。真的很高兴能得到这个解决方案!):只是一个小问题……如果我不得不在竞争性编程问题中加入输入,我应该用什么方法?悬而未决的是行的长度以及需要进行什么样的解析才能从行中获取所需的内容。在这种情况下,由于行如此短且没有解析,因此
或getchar
读取和存储每行中的4个字符的速度与其他任何操作一样快。如果行的长度大于32个字符,请查看fgets
或getline
。几乎没有任何情况下scanf
会因为f的可变性质而表现得更好函数。我已经编写了性能同样出色的getchar
和getline
变体。如果你想最大限度地提高速度,请查看getchar\u unlocked
和fgetc\u unlocked
版本的函数,这些函数与非\u unlocked
版本相比,速度稍有优势。(有关详细信息,请参阅:man 3 getchar\u unlocked
)
$ printf "4 4\n####\n#5 #\n## #\n#E #\n" | ./bin/scanf_loop
line[ 0] : ####
line[ 1] : #5 #
line[ 2] : ## #
line[ 3] : #E #
$ printf "4 4\n####\n#5 #\n## #\n#E #\n" | valgrind ./bin/scanf_loop
==11065== Memcheck, a memory error detector
==11065== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==11065== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==11065== Command: ./bin/scanf_loop
==11065==
line[ 0] : ####
line[ 1] : #5 #
line[ 2] : ## #
line[ 3] : #E #
==11065==
==11065== HEAP SUMMARY:
==11065== in use at exit: 0 bytes in 0 blocks
==11065== total heap usage: 5 allocs, 5 frees, 52 bytes allocated
==11065==
==11065== All heap blocks were freed -- no leaks are possible
==11065==
==11065== For counts of detected and suppressed errors, rerun with: -v
==11065== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)