Comportamiento inesperado al imprimir una matriz de caracteres en C

Recientemente encontré un tema interesante en un fragmento de código que tuve que escribir. Aunque solucioné el problema utilizando un enfoque diferente al original, me gustaría ver si alguien tiene alguna idea de por qué el original no funcionó. Aquí están los fragmentos de código condensados.

Código original:

int i, j, k; for (i=0; i!=10, (result = fgets(newline, 1024, stream))!=NULL; i++) { result = strtok(newline, " "); for (j=0; j!=x; j++) { for (k=0; k!=y; k++) { score_matrix[i][j][k] = result; printf("%d ", atoi(score_matrix[i][j][k])); result = strtok(NULL, " "); } } printf("\n"); } 

En el código anterior, `stream ‘es un archivo CSV. De todos modos, el código anterior imprime el archivo CSV como se supone que es:

 19 17 20 18 9 6 10 9 12 11 10 16 3 7 9 10 0 5 8 6 15 13 15 15 20 18 18 16 17 19 19 18 13 15 14 12 10 13 18 15 

Sin embargo, cuando tomo el mismo código exacto que el de arriba, solo elimino algunas líneas irrelevantes:

 int i, j, k; for (i=0; i!=10; i++) { for (j=0; j!=x; j++) { for (k=0; k!=y; k++) { printf("%d ", atoi(score_matrix[i][j][k])); } } printf("\n"); } 

Se imprime:

 10 13 18 15 10 0 3 8 10 13 18 15 10 0 3 18 10 0 3 18 10 13 18 15 10 13 18 15 10 13 18 15 10 13 18 15 10 13 18 15 

Lo que está muy mal. Código fijo (que no hace más que convertir la matriz a int , y elimina el atoi ):

 int i, j, k; for (i=0; i!=10, (result = fgets(newline, 1024, stream))!=NULL; i++) { result = strtok(newline, " "); for (j=0; j!=x; j++) { for (k=0; k!=y; k++) { score_matrix[i][j][k] = atoi(result); printf("%d ", score_matrix[i][j][k]); result = strtok(NULL, " "); } } printf("\n"); } 

y

 int i, j, k; for (i=0; i!=10; i++) { for (j=0; j!=x; j++) { for (k=0; k!=y; k++) { printf("%d ", score_matrix[i][j][k]); } } printf("\n"); } 

Ahora ambos imprimen lo correcto:

 19 17 20 18 9 6 10 9 12 11 10 16 3 7 9 10 0 5 8 6 15 13 15 15 20 18 18 16 17 19 19 18 13 15 14 12 10 13 18 15 

Tal vez me esté perdiendo algo obvio aquí, pero tengo mucha curiosidad por saber por qué sucede esto.

EDITAR:

  • x -> pasado por el argumento. En este caso es 2.
  • score_matrix -> El código incorrecto es char* score_matrix[10][x][y]; , en el bien es int score_matrix[10][x][y];
  • newline -> char newline[1024];
  • result -> char* result;
  • Además, el resultado ha sido validado con sentencias de printf.

Su uso repetido de la misma fila de búfer es incorrecto. La salida de la primera muestra lo está convirtiendo en una falsa sensación de éxito cuando en realidad es todo menos correcto. La modificación del bucle para volcar la dirección del token extraído y el guardado mostrará evidencia de esto:

 score_matrix[i][j][k] = result; printf("%p ", result); result = strtok(NULL, " "); 

Verá que muchos de sus tokens en el cubo de salida comparten las mismas direcciones de búfer, lo que, por supuesto, se debe a que está pasando la newline línea de búfer de newline para cada tokenización, y en el proceso de borrado del contenido en cualquier bucle anterior.

Si desea almacenar caracteres reales char * puede hacerlo , pero a menos que tenga que hacerlo , no lo haga . En su lugar, haga lo que una de sus versiones fijas: convierta a int y almacene el int como el valor de matriz. De lo contrario, necesitarás algo como esto para cargar:

 int i, j, k; for (i=0; i!=10, (result = fgets(newline, 1024, stream))!=NULL; i++) { result = strtok(newline, " "); for (j=0; j!=x; j++) { for (k=0; k!=y; k++) { score_matrix[i][j][k] = strdup(result); // NOTE: POSIX strdup() function printf("%d ", atoi(score_matrix[i][j][k])); result = strtok(NULL, " "); } } printf("\n"); } 

Lo que más tarde requerirá una limpieza de hella para todas esas asignaciones dinámicas. Podría hacer una única asignación de mondo que cargue todo el archivo en la memoria como un único búfer dynamic de caracteres y alterar considerablemente sus bucles de análisis, pero le aconsejo que incluso menos de lo que recomiendo el enfoque de asignación dinámica de un solo token.