不能打破一个循环。读取未定义的数组大小

时间:2017-05-13 22:20:59

标签: c

我有这个字母和数字序列,其中字母总是这四个:s,S,m,M。数字可以有任何值。由于没有给出序列的大小,我只是不能使用 for循环,所以我决定使用while循环,但是我遇到了打破循环的问题。

一些输入示例是:

12 s 80 s 3 m 12 M 240 S 8 m 30 s 240 s 1440 S 8 m 18 s 60 M

5 m 120 s 30 s 360 S 6 M 5 s 42 S 36 M 8 m 66 M 3240 S 14 m

到目前为止,这是我的代码:

#include <stdio.h>

int main () {

int n[100], i = 0;
char x[100];

while(x[i] != '\n')
{
 scanf(" %d %c", &n[i], &x[i]);
 printf("%d %c ", n[i], x[i]);
 i++;
}

return 0;
}

如何打破循环,并将所有这些值正确保存在阵列上?

2 个答案:

答案 0 :(得分:0)

像这样

array(5) { ["username"]=> string(0) "" ["password1"]=> string(0) "" ["password2"]=> string(0) "" ["email"]=> string(0) "" ["submitted"]=> string(0) "" } 
#include <stdio.h>

int main(void){
    int n[100], i, j;
    char x[100];

    do {
        for(i = 0; i < 100; ++i){
            int ch;
            while((ch = getchar()) != EOF && ch != '\n'){//check newline
                if(ch == '-' || '0' <= ch && ch <= '9'){
                    ungetc(ch, stdin);//back to stream a character
                    break;
                }
            }
            if(ch == EOF || ch == '\n')
                break;
            if(2 != scanf("%d %c", &n[i], &x[i])){
                fprintf(stderr, "invalid format.\n");
                i = 0;//End the outer do-while loop
                break;
            }
        }
        //print
        for(j = 0; j < i; ++j){
            printf("(%d, %c)", n[j], x[j]);
        }
        printf("\n");
    } while(i != 0);//End with empty line
}

答案 1 :(得分:0)

scanf and fscanf have many problems所以最好避免它们。

处理输入的一般模式是创建一个大的输入缓冲区,然后将其处理成更小的块。

char line[4096];
fgets( line, sizeof(line), stdin );

由于line被重用,所以可以使它足够大以容纳任何合理的输入。

现在您已经在内存中读取了一行,它是一个已知大小的字符串,可以根据需要进行处理。 sscanf(字符串上的scanf)没有scanf的大部分问题,但它也不适合移动字符串。一种方法是使用strtok将字符串拆分为空格上的标记,并将它们交替处理为字母和数字。

const char sep[] = " \t\n";
bool expect_letter = false;
for(
    char *token = strtok( line, sep );
    token != NULL;
    token = strtok( NULL, sep )
) {
    if( expect_letter ) {
        printf("Letter %s\n", token);
        expect_letter = false;
    }
    else {
        printf("Number %s\n", token);
        expect_letter = true;
    }    
}

如果你想将它们存储在数组中,那么分配你希望足够的内存是不好的做法。您将不得不使用根据需要增长的数组。 C没有这些内置。你可以编写自己的,这是一个很好的练习,但很容易出错。对于制作use one from a library such as Glib

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>

int main() {
    // Read a single line of input into a buffer.
    char line[4096];
    fgets( line, sizeof(line), stdin );

    // Create arrays to hold letters and numbers, these will grow as needed.
    GArray *numbers = g_array_new( FALSE, TRUE, sizeof(int) );
    GArray *letters = g_array_new( FALSE, TRUE, sizeof(char) );

    // Split the string on whitespace into tokens.
    const char sep[] = " \t\n";
    gboolean expect_letter = FALSE;
    for(
        char *token = strtok( line, sep );
        token != NULL;
        token = strtok( NULL, sep )
    ) {
        if( expect_letter ) {
            // Need an error check to ensure that `token` is a single character.
            g_array_append_val( letters, token[0] );
            expect_letter = FALSE;
        }
        else {
            // strtol is a better choice, it has error checking
            int num = atoi(token);
            g_array_append_val( numbers, num );
            expect_letter = TRUE;
        }
    }

    // Print the numbers and letters.
    for( guint i = 0; i < letters->len; i++ ) {
        printf(
            "%d%c\n",
            g_array_index( numbers, int, i ),
            g_array_index( letters, char, i )
        );
    }
}

请注意,GLib提供了自己的布尔值,所以我切换到了它而不是stdbool来保持一致。

如评论中所述,这不包括检查令牌是否符合预期。也可以使用没有字母的数字,因此检查lettersnumbers的大小是否相同会很好。或者你可以创建一个结构来保存字母/数字对,并有一个结构列表。