PDA

View Full Version : C. average from string problem with strtok.



Iurie_Nunu
July 16th, 2016, 06:43 PM
Hi everyone i'm practicing with C, this program takes numbers in input but in string and divided with commas ("1,2,3,4") and the output is the average of the numbers. I don't know where I go wrong but it gives me always segmentation fault, can anybody help me?



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




float* split(char* string){

int dim=0;
int i=0;
float numero;

char* sep = "," ;
char* tokena;
char* token;
char* stringa;
strcpy (stringa, string);


for(token=strtok(stringa,sep); token!=NULL; token=strtok(NULL,sep))
{
dim++;
}


float *vet = (float*)malloc (dim*sizeof(float));

for(tokena=strtok(string,sep); tokena!=NULL; tokena=strtok(NULL,sep))
{
numero=atof(tokena);
vet[i]=numero;
i++;
}

return vet;
}






float average(char* stringa){

int i;
int dim=0;
char* token;
char* sep = ",";
float sum=0;
float risultato=0;
char* stringas;
strcpy(stringas, stringa);

for(token=strtok(stringas,sep); token!=NULL; token=strtok(NULL,sep))
{
dim++;
}


float* vettore = split(stringa);
for(i=0;i<dim;i++){

sum = sum + vettore[i];
}

risultato = (sum/dim);


return risultato;


}










int main()
{
char* prova="3,2,1";
float a;
a=average(prova);
printf("%f\n", a);
return 0;
}

spjackson
July 16th, 2016, 07:18 PM
for(token=strtok(stringa,sep); token!=NULL; token=strtok(NULL,sep))

That is ok, but the following isn't.


for(tokena=strtok(string,sep); tokena!=NULL; tokena=strtok(NULL,sep))

This attempts to write to the read-only string "3,2,1". One solution is


int main()
{
char test[] ="3,2,1";

Iurie_Nunu
July 16th, 2016, 08:02 PM
It didn't worked...I've tried also with char* test= strdup("1,2,3") but nothing :(

spjackson
July 16th, 2016, 10:02 PM
I compiled your code, ran it and got a segmentation fault, debugged with gdb, made the correction I suggested and ran it again with a segmentation fault. If you are still getting the same fault, I'm afraid that I don't know what would be causing that.

steeldriver
July 16th, 2016, 11:00 PM
As you'll notice if you compile with the `-Wall` flag



badav2.c: In function ‘average’:
badav2.c:53:7: warning: ‘stringas’ is used uninitialized in this function [-Wuninitialized]
strcpy(stringas, stringa);
^

i.e. you don't actually allocate any memory for `stringas` before you `strcpy` to it:



char* stringas;
strcpy(stringas, stringa);


(it's just a pointer to some random memory) although the program actually seems to survive until the subsequent strtok:



Breakpoint 1, average (stringa=0x7fffffffdf50 "3,2,1") at badav2.c:55
55 for(token=strtok(stringas,sep); token!=NULL; token=strtok(NULL,sep))
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
_


There's a similar issue with `stringa`



char* stringa;
strcpy (stringa, string);

dwhitney67
July 19th, 2016, 10:49 PM
The segmentation fault is likely occurring because you are operating on a (const) string literal.

If you read the man-page for strtok(), ironically in the section entitled BUGS, you will see that strtok() modifies the first argument. The precludes the usage of a string literal as your first argument.

You should consider accepting a string as a command line argument; for example,


./myprog "3,2,1"


As for your code, try to keep it simple. All you really have to do to compute an average of numbers is:

1. Parse (tokenize) string
2. Keep a sum of the values.
3. Keep a count of the values.
4. Compute average (i.e. sum/count)
5. Print average

To convert a token value to a float, use atof(), or preferably strtof().

P.S. Be careful when mixing usages of strdup() and strtok(). The latter advances the pointer to the next token (if any). If you lose a reference to the original pointer returned by strdup(), then you will undoubtedly have a memory leak.



char* data = strdup("3,2,1");
char* prova = data;

...

free(data);

...