如何输入n行字符串,每行包含m个字符,其中可能包含空格作为字符?

时间:2015-09-21 02:31:21

标签: 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(i=0;i<n;i++)
    scanf("%[^\n]%*c", a[i]);
 }
/*An example of input would be:
4 4
####
#S #
## #
#E #
*/

2 个答案:

答案 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函数,如fgetsgetline。即使是面向字符的函数,如getchar()fgetc,也可以提供大量灵活的输入处理。也就是说,scanf确实有它的位置,但与其他一切一样,它有其优点和缺点。只需将它们与你工作所需的重量相加即可。

转到您的代码。怎么了?评论中指出了许多小事。最大的是char **a=(char**)malloc(n);。您只需分配n个字节的存储空间, n 指针。每个指针都是48个字节(通常为32/64位框)。因此,您的分配至少需要:

char **a = malloc (n * sizeof *a);  /* don't cast the return */

下一期,您正试图填充for循环中的行。虽然您可能收到了一些n,但无法保证您实际上要读取那么多行数据。如果你不这样做,那么你就是强迫代码读取和分配不存在的输入。 while循环在这里可能会更好一些。

分配内存时,需要保留指向每个分配开头的指针,以便在不再需要时释放它。只要习惯跟踪你分配的内存并在完成后释放它。当你退出时它被释放,当你开始编写分配内存的函数时,如果你没有正确管理它的习惯,你的代码会像筛子一样泄漏。

现在,有一点需要注意,我们都明白使用fgetsgetline是首选方法,而以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)