tipos - ¿Por qué recibo una falla de segmentación?
segmentación de mercado marketing (8)
Hola chicos, intento escribir un programa que tome un archivo de texto plano como argumento y lo analice, agregue todos los números y luego imprima la suma. El siguiente es mi código:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static int sumNumbers(char filename[])
{
int sum = 0;
FILE *file = fopen(filename, "r");
char *str;
while (fgets(str, sizeof BUFSIZ, file))
{
while (*str != ''/0'')
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
str++;
}
}
fclose(file);
return sum;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Please enter the filename as the argument./n");
exit(EXIT_FAILURE);
}
else
{
printf("The sum of all the numbers in the file is : %d/n", sumNumbers(argv[1]));
exit(EXIT_SUCCESS);
}
return 0;
}
Y el archivo de texto que estoy usando es:
Este es un archivo de texto bastante aburrido con algunos números aleatorios dispersos por todo.
Aquí hay uno: 87 y aquí hay otro: 3
y finalmente dos últimos números: 12 19381. Listo. Uf.
Cuando compilo y trato de ejecutarlo, aparece un error de segmentación.
Aquí hay una función que hace su trabajo:
static int sumNumbers(char* filename) {
int sum = 0;
FILE *file = fopen(filename, "r");
char buf[BUFSIZ], *str;
while (fgets(buf, BUFSIZ, file))
{
str=buf;
while (*str)
{
if (isdigit(*str))
{
sum += strtol(str, &str, 10);
}
str++;
}
}
fclose(file);
return sum;
}
Esto no incluye el manejo de errores, pero funciona bastante bien. Para su archivo, la salida será
La suma de todos los números en el archivo es: 19483
Has declarado char * str, pero aún no has reservado memoria para ello. Necesitarás malloc memoria para ello.
Muchos errores relacionados con la memoria como este se pueden encontrar fácilmente con valgrind. Recomiendo usarlo como una herramienta de depuración.
No ha asignado ninguna memoria para poblar str
. fgets
toma como primer argumento un búfer, no un puntero no asignado.
En lugar de char *str;
necesita definir un búfer de tamaño razonable, por ejemplo, char str[BUFSIZ];
No has asignado espacio para el buffer.
El puntero str
es solo un puntero colgante. Por lo tanto, su programa vacía los datos leídos del archivo en la ubicación de la memoria que usted no posee, lo que lleva a la falla de segmentación.
Necesitas:
char *str;
str = malloc(BUFSIZ); // this is missing..also free() the mem once done using it.
o solo:
char str[BUFSIZ]; // but then you can''t do str++, you''ll have to use another
// pointer say char *ptr = str; and use it in place of str.
EDITAR:
Hay otro error en:
while (fgets(str, sizeof BUFSIZ, file))
El segundo argumento debe ser BUFSIZ
no sizeof BUFSIZ
.
¿Por qué?
Porque el segundo argumento es la cantidad máxima de caracteres que se deben leer en el búfer, incluido el carácter nulo. Como sizeof BUFSIZ
es 4
, puede leer max hasta 3
en el búfer. Es por eso que 19381
se leía como 193
y luego 81<space>
.
Porque no has asignado espacio para tu buffer.
Su programa tiene varios errores:
- No maneja líneas largas correctamente. Cuando lee un búfer de algún tamaño, puede suceder que un número comience al final del búfer y continúe al comienzo del siguiente búfer. Por ejemplo, si tiene un búfer de tamaño 4, podría existir la entrada
The |numb|er 1|2345| is |larg|e.
The |numb|er 1|2345| is |larg|e.
, donde las líneas verticales indican los contenidos del búfer. Luego contarías el 1 y el 2345 por separado. - Llama a
isdigit
con unchar
como argumento. Tan pronto como lea cualquier carácter "grande" (mayor queSCHAR_MAX
), el comportamiento no está definido . Su programa puede fallar o producir resultados incorrectos o hacer lo que quiera hacer. Para solucionar esto, primero debe convertir el valor en ununsigned char
, por ejemplo,isdigit((unsigned char) *str)
. O, como en mi código, puede alimentarlo con el valor de la funciónfgetc
, que garantiza que es un argumento válido paraisdigit
. - Utiliza una función que requiere un búfer (
fgets
) pero no asigna el búfer. Como otros señalaron, la manera más fácil de obtener un búfer es declarar unchar buffer[BUFSIZ]
local variablechar buffer[BUFSIZ]
. - Utiliza la variable
str
para dos propósitos: mantener la dirección del búfer (que debe permanecer constante durante todo el tiempo de ejecución) y el puntero para analizar el texto (que cambia durante la ejecución). Haz estas dos variables. Yo los llamaríabuffer
yp
(abreviatura de puntero ).
Aquí está mi código:
#include <ctype.h>
#include <stdio.h>
static int sumNumbers(const char *filename)
{
int sum, num, c;
FILE *f;
if ((f = fopen(filename, "r")) == NULL) {
/* TODO: insert error handling here. */
}
sum = 0;
num = 0;
while ((c = fgetc(f)) != EOF) {
if (isdigit(c)) {
num = 10 * num + (c - ''0'');
} else if (num != 0) {
sum += num;
num = 0;
}
}
if (fclose(f) != 0) {
/* TODO: insert error handling here. */
}
return sum;
}
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++)
printf("%d/t%s/n", sumNumbers(argv[i]), argv[i]);
return 0;
}
Varias personas ya han abordado el problema sobre el que preguntaste, pero a cambio tengo una pregunta. ¿Qué crees exactamente que esto logra?
if (isdigit(*str))
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
}
¿Qué se supone que es el punto de dos sucesivas declaraciones if
con exactamente la misma condición? (Nota para el registro: ninguno tiene una cláusula else
).
char *str;
str no tiene memoria asignada. Utilice malloc () para asignar memoria o para declararlo con un tamaño predefinido.
char str[MAX_SIZE];