Poner números separados por un espacio en una matriz

Quiero que un usuario ingrese números separados por un espacio y luego almacene cada valor como un elemento de una matriz. Actualmente tengo:

while ((c = getchar()) != '\n') { if (c != ' ') arr[i++] = c - '0'; } 

pero, por supuesto, esto almacena un dígito por elemento.

Si el usuario tuviera que escribir:

 10 567 92 3 

Quería que el valor 10 se almacenara en arr[0] , y luego 567 en arr[1] etc.

¿Debería usar scanf lugar de alguna manera?

Hay varios enfoques, dependiendo de qué tan robusto quieres que sea el código.

Lo más sencillo es usar scanf con el especificador de conversión %d :

 while (scanf("%d", &a[i++]) == 1) /* empty loop */ ; 

El especificador de conversión %d le dice a scanf que omita cualquier espacio en blanco inicial y lea hasta el siguiente carácter sin dígitos. El valor de retorno es el número de conversiones y asignaciones exitosas. Ya que estamos leyendo un solo valor entero, el valor de retorno debe ser 1 en caso de éxito.

Como está escrito, esto tiene una serie de escollos. Primero, suponga que su usuario ingresa más números de los que su matriz tiene el tamaño para retener; Si tienes suerte, obtendrás una infracción de acceso inmediatamente. Si no lo eres, acabarás obstruyendo algo importante que causará problemas más adelante (los desbordamientos de búfer son una explotación de malware común).

Por lo tanto, al menos desea agregar código para asegurarse de no pasar del final de su matriz:

 while (i < ARRAY_SIZE && scanf("%d", &a[i++]) == 1) /* empty loop */; 

Bien hasta ahora. Pero ahora suponga que su usuario fatiga un carácter no numérico en su entrada, como 12 3r5 67 . Como está escrito, el bucle asignará 12 a a[0] , 3 a a[1] , luego verá la r en el flujo de entrada, devolverá 0 y saldrá sin guardar nada en a[2] . Aquí es donde aparece un error sutil: aunque no se asigna nada a a[2] , la expresión i++ aún se evalúa, por lo que pensará que asignó algo a a[2] aunque contenga un valor de basura. Por lo tanto, es posible que desee evitar el incremento de i hasta que sepa que tuvo una lectura exitosa:

 while (i < ARRAY_SIZE && scanf("%d", &a[i]) == 1) i++; 

Idealmente, te gustaría rechazar 3r5 completo. Podemos leer el carácter inmediatamente después del número y asegurarnos de que sea espacio en blanco; Si no es así, rechazamos la entrada:

 #include  ... int tmp; char follow; int count; ... while (i < ARRAY_SIZE && (count = scanf("%d%c", &tmp, &follow)) > 0) { if (count == 2 && isspace(follow) || count == 1) { a[i++] = tmp; } else { printf ("Bad character detected: %c\n", follow); break; } } 

Si obtenemos dos conversiones exitosas, nos aseguramos de que follow sea ​​un carácter de espacio en blanco; si no lo es, imprimimos un error y salimos del bucle. Si obtenemos 1 conversión exitosa, eso significa que no hubo caracteres después del número de entrada (lo que significa que pulsamos EOF después de la entrada numérica).

Alternativamente, podemos leer cada valor de entrada como texto y usar strtol para hacer la conversión, lo que también le permite detectar el mismo tipo de problema (mi método preferido):

 #include  #include  ... char buf[INT_DIGITS + 3]; // account for sign character, newline, and 0 terminator ... while(i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL) { char *follow; // note that follow is a pointer to char in this case int val = (int) strtol(buf, &follow, 10); if (isspace(*follow) || *follow == 0) { a[i++] = val; } else { printf("%s is not a valid integer string; exiting...\n", buf); break; } } 

¡PERO ESPERA HAY MAS!

Supongamos que su usuario es uno de esos tipos de control de calidad retorcidos a los que le gusta lanzar información desagradable a su código "solo para ver qué sucede" y que ingresa un número como 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 que obviamente es demasiado grande para ajustarse a cualquiera de los tipos de enteros estándar. Lo creas o no, scanf("%d", &val) no va a funcionar en esto, y terminará almacenando algo en val , pero una vez más, es una entrada que probablemente te gustaría rechazar.

Si solo permite un valor por línea, esto es relativamente fácil de proteger; fgets almacenará un carácter de nueva línea en el búfer de destino si hay espacio, así que si no vemos un carácter de nueva línea en el búfer de entrada, el usuario escribió algo que es más largo de lo que estamos preparados para manejar:

 #include  ... while (i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL) { char *newline = strchr(buf, '\n'); if (!newline) { printf("Input value too long\n"); /** * Read until we see a newline or EOF to clear out the input stream */ while (!newline && fgets(buf, sizeof buf, stdin) != NULL) newline = strchr(buf, '\n'); break; } ... } 

Si desea permitir varios valores por línea, como '10 20 30 ', esto se vuelve un poco más difícil. Podríamos volver a leer caracteres individuales de la entrada y hacer una verificación de cordura en cada uno de ellos (advertencia, sin probar):

 ... while (i < ARRAY_SIZE) { size_t j = 0; int c; while (j < sizeof buf - 1 && (c = getchar()) != EOF) && isdigit(c)) buf[j++] = c; buf[j] = 0; if (isdigit(c)) { printf("Input too long to handle\n"); while ((c = getchar()) != EOF && c != '\n') // clear out input stream /* empty loop */ ; break; } else if (!isspace(c)) { if (isgraph(c) printf("Non-digit character %c seen in numeric input\n", c); else printf("Non-digit character %o seen in numeric input\n", c); while ((c = getchar()) != EOF && c != '\n') // clear out input stream /* empty loop */ ; break; } else a[i++] = (int) strtol(buffer, NULL, 10); // no need for follow pointer, // since we've already checked // for non-digit characters. } 

Bienvenido al maravilloso mundo de información interactiva en C.

Pequeño cambio en su código: solo incremente i cuando lea el espacio:

 while ((c = getchar()) != '\n') { if (c != ' ') arr[i] = arr[i] * 10 + c - '0'; else i++; } 

Por supuesto, es mejor usar scanf :

 while (scanf("%d", &a[i++]) == 1); 

siempre que tengas suficiente espacio en la matriz. Además, tenga cuidado de que el while arriba termina con ; , todo se hace dentro de la condición de bucle.

De hecho, cada valor de retorno debe ser verificado.

Esto funcionará …

 #include void main() { int i=0,j,arr[100]; while(scanf("%d",&arr[i])!=-1) { i++; } for(j=0;j