这是我的代码,试图采取不。 (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(i=0;i<n;i++)
scanf("%[^\n]%*c", a[i]);
}
/*An example of input would be:
4 4
####
#S #
## #
#E #
*/
答案 0 :(得分:0)
松散纠正
// scanf("%d%d",&n,&m); change to
scanf("%d %d%*c",&n,&m); // better suggestion
考虑输入格式这是必要的
和
// char **a=(char**)malloc(n); change to
char **a=malloc(n * sizeof( char *) );
并且,由于某种原因,m和以下循环是混合的
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<n;i++) { // for n pointers
a[i] = malloc ( m * sizeof(char) ); // allocate memory
fgets( a[i], m, stdin ); // scan string
// optionally add this line
//a[ strlen(a[i]) - 1 ] = '\0'; // null terminate optionally
a[i][strcspn(a[i], "\n")] = '\0'; // another awesome suggestion
}
m的大小是扫描字符串时的关键,确保有足够的字节可用于&#39; \ n&#39;和&#39; \ 0&#39;值得分配实际内存+ 2
答案 1 :(得分:0)
你问&#34;但是在处理输入时我的代码出了什么问题?&#34;在评论中。一个公平的问题。根据您的经验,您收到的建议是如何避免尝试使用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
循环在这里可能会更好一些。
分配内存时,需要保留指向每个分配开头的指针,以便在不再需要时释放它。只要习惯跟踪你分配的内存并在完成后释放它。当你退出时它被释放,当你开始编写分配内存的函数时,如果你没有正确管理它的习惯,你的代码会像筛子一样泄漏。
现在,有一点需要注意,我们都明白使用fgets
或getline
是首选方法,而以newline
开头的行将是一个问题,您可以编写代码使用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;
}
<强>输入强>
$ printf "4 4\n####\n#5 #\n## #\n#E #\n"
4 4
####
#5 #
## #
#E #
<强>编译强>
gcc -Wall -Wextra -o bin/scanf_loop scanf_loop.c
<强>输出强>
$ 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)