问题
I'm not a good English speaker.
so in my program I want to copy a text who exists in a txt file to an array.
typedef struct Chaine
{
char * Lachaine;
int Taille_C;
} Chaine ;
int main (void)
{
Chaine *Tab_Texte=NULL;
Tab_Texte=(Chaine*)malloc(sizeof(Chaine));
FILE* Texte= NULL;
Texte = fopen("chaines", "r");
fseek(Texte, 0, SEEK_END);
Tab_Texte->Taille_C=ftell(Texte);
fseek(Texte, 0, SEEK_SET);
Tab_Texte->Lachaine=NULL;
Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C);
fread(Tab_Texte->Lachaine,sizeof(char)*(Tab_Texte->Taille_C),1,Texte);
printf("%s",Tab_Texte->Lachaine);
return 0;
}
Here everything works great and when I change
Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C);
with ( for example )
Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C - 10);
It works always, It suppose to show me a segmentation fault because sizeof(char)*Tab_Texte->Taille_C - 10
is shorter than sizeof(char)*Tab_Texte->Taille_C
so than the text in the file.
Can you tell me why it always works?
回答1:
What you're experiencing is called undefined behavior.
- Accessing past the allocated memory
- Using a not-null terminated char array as string
- supplying invalid file pointer
all [any] of these will result in undefined behavior and the side effect may be a segmentation fault, but it's not guaranteed.
Please
- Check for the success of
fopen()
before using the returned pointer - null-terminate a char array to use it as a string
free()
the allocated memory after the usage is over.- Do not cast the return value of
malloc()
/calloc()
.
回答2:
The reason why it works always is because what you describe is undefined behavior
so it's not really defined what should happen.
In some situations it may lead to a segmentation fault
but not always. So your always is really sometimes, but it turns out the conditions haven't been the right ones for the segmentation fault
to happen.
Consider the following fixes to your code:
You should not do this
printf("%s",Tab_Texte->Lachaine);
since your
Tab_Texte->Lachaine
is not null terminatedYou can try to do it like this
fwrite(Tab_Texte->Lachaine, 1, Tab_Texte->Taille_C, stdout);
but generally you never check for every single function that returns null on failure in your code.
For example
Texte = fopen("chaines", "r"); if (Texte == NULL) weAreInTroubleIfWeCall_fread_OnTexte_SoAbort();
also applies for
malloc
, and you don't need to castmalloc
, read thisYou should
free
the result ofmalloc
when you no longer need it.
回答3:
You will get a segfault is you read or write to memory that is not allocated for your program. If you misuse malloc, you may not get a segfault, depending on the way the underlying operating system loads your program into memory. In that case, you may be writing or reading from your own memory, but in different locations, potentially overwriting other variables.
回答4:
// the reason a seg fault event did not occur is because // the code is using the contents of the field: Tab_Texte->Taille_C // which is the full size of the file // (so no problem unless file has less than 10 bytes)
//eliminate a lot of clutter in your code via proper definition of a struct rather that a typedef
//do not cast the returned value from malloc (and family)
//check the returned value from malloc to assure successful operation
//check the returned value from fopen to assure successful operation
//check the returned value from fseek to assure successful operation
//check the returned value from ftell to assure successful operation
//cleanup when exiting program, including free for malloc'd areas, closing files, etc
//check the returned value from fread to assure successful operation
#include <stdio.h> // fopen(), fclose(), fread(), fseek(), ftell()
#include <stdlib.h> // exit(), EXIT_FAILURE, free(), malloc()
struct Chaine
{
char * Lachaine;
int Taille_C;
};
int main (void)
{
struct Chaine *Tab_Texte=NULL;
if( NULL == (Tab_Texte=malloc(sizeof(struct Chaine)) ) )
{ // then, malloc failed
perror("malloc failed");
exit( EXIT_FAILURE );
}
// implied else, malloc successful
FILE* Texte= NULL;
if(NULL == (Texte = fopen("chaines", "r")) )
{ // then fopen failed
perror( "fopen failed for chaines for read");
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fopen successful
if( 0 != fseek(Texte, 0, SEEK_END) )
{ // then fseek failed
perror( "fseek for end of file failed" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fseek successful
if( -1L == (Tab_Texte->Taille_C=ftell(Texte) ) )
{ // then ftell failed
perror("ftell failed" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, ftell successful
if( 0 != fseek(Texte, 0, SEEK_SET) )
{ // then fseek failed
perror( "fseek for start of file failed" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fseek successful
Tab_Texte->Lachaine=NULL;
if( NULL == (Tab_Texte->Lachaine=malloc(Tab_Texte->Taille_C) ) )
{ // then, malloc failed
perror( "malloc failed for file size" );
fclose(Texte);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, malloc successful
if( 1 != fread(Tab_Texte->Lachaine, sizeof(Tab_Texte->Taille_C), 1 , Texte) )
{ // fread failed
perror( "fread for whole file failed" );
fclose(Texte);
free(Tab_Texte->Lachaine);
free(Tab_Texte);
exit( EXIT_FAILURE );
}
// implied else, fread successful
printf("%s",Tab_Texte->Lachaine);
// cleanup
fclose(Texte);
free(Tab_Texte->Lachaine);
free(Tab_Texte);
return 0;
} // end function: main
来源:https://stackoverflow.com/questions/27730460/no-segmentation-fault-for-accessing-out-of-bound-memory