访问超出范围的内存没有分段错误

时间:2015-01-01 11:41:45

标签: c segmentation-fault dynamic-arrays

我不是一位优秀的英语人士。

所以在我的程序中,我想将存在于txt文件中的文本复制到数组中。

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;
}

这里一切都很好,当我改变时

Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C);

与(例如)

Tab_Texte->Lachaine=(char*)malloc(sizeof(char)*Tab_Texte->Taille_C - 10);

它始终有效,它假设向我显示分段错误,因为sizeof(char)*Tab_Texte->Taille_C - 10sizeof(char)*Tab_Texte->Taille_C短,而不是文件中的文本。

你能告诉我为什么它总是有效吗?

4 个答案:

答案 0 :(得分:5)

您遇到的问题称为undefined behavior

  • 访问已分配的内存
  • 使用非空终止的char数组作为字符串
  • 提供无效文件指针

所有这些都将导致未定义的行为,副作用可能是分段错误,但不能保证。

  1. 在使用返回的指针
  2. 之前检查fopen()是否成功
  3. null-terminate char数组以将其用作字符串
  4. free()使用结束后分配的内存。
  5. 请勿转换malloc() / calloc()
  6. 的返回值

答案 1 :(得分:3)

它始终有效的原因是因为你所描述的是undefined behavior所以它并没有真正定义应该发生什么。

在某些情况下,它可能导致segmentation fault,但并非总是如此。所以你总是有时候,但事实证明segmentation fault发生的条件并不合适。

请考虑对您的代码进行以下修复:

  1. 你不应该这样做

    printf("%s",Tab_Texte->Lachaine);
    

    因为Tab_Texte->Lachaine未终止

  2. 您可以尝试这样做

    fwrite(Tab_Texte->Lachaine, 1, Tab_Texte->Taille_C, stdout);
    

    但通常你不会检查代码中失败时返回null的每个函数。

    例如

    Texte = fopen("chaines", "r");
    if (Texte == NULL)
        weAreInTroubleIfWeCall_fread_OnTexte_SoAbort();
    

    也适用于malloc,您不需要投射malloc,阅读this

  3. 当您不再需要free时,malloc的结果应该{{1}}。

答案 2 :(得分:1)

如果您读取或写入未分配给您的程序的内存,您将收到段错误。如果您滥用malloc,则可能无法获得段错误,具体取决于底层操作系统将程序加载到内存中的方式。在这种情况下,您可能在自己的记忆中书写或阅读,但在不同的位置,可能会覆盖其他变量。

答案 3 :(得分:1)

//没有发生seg故障事件的原因是因为 //代码正在使用字段的内容:Tab_Texte-> Taille_C //这是文件的完整大小 //(除非文件少于10个字节,否则没问题)

//通过正确定义struct而不是typedef来消除代码中的大量混乱

//不要从malloc(和family)中转换返回的值

//检查malloc返回的值以确保操作成功

//检查fopen返回的值以确保操作成功

//检查fseek返回的值以确保操作成功

//检查来自ftell的返回值以确保成功操作

//退出程序时清理,包括免费使用malloc&d; d区域,关闭文件等

//检查来自fread的返回值以确保成功操作

#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