C中未初始化的指针在MinGW中工作得出人意料

C中未初始化的指针在MinGW中工作得出人意料,c,pointers,C,Pointers,我的朋友给我发了这段代码,说如果我能找到任何问题,我检查了代码,发现他使用的是未初始化的指针int*ptr并告诉他,但他说这段代码有效,所以我复制了代码并用gcc编译了它,它在执行时给了我分段错误(内核转储),但他声称这段代码有效,并给了我一个屏幕截图(他在Dev-C++中使用MinGW) 所以问题是,当使用未初始化的指针时,为什么这段代码在MinGW中工作 #include<stdio.h> int main() { int size,i,j,sum=0; puts

我的朋友给我发了这段代码,说如果我能找到任何问题,我检查了代码,发现他使用的是未初始化的指针
int*ptr
并告诉他,但他说这段代码有效,所以我复制了代码并用gcc编译了它,它在执行时给了我分段错误(内核转储),但他声称这段代码有效,并给了我一个屏幕截图(他在Dev-C++中使用MinGW)

所以问题是,当使用未初始化的指针时,为什么这段代码在MinGW中工作

#include<stdio.h>
int main() {
    int size,i,j,sum=0;
    puts("enter1");
    scanf("%d",&size);
    int arr1[size];
    puts("enter1");
    int *ptr;
    for(i=0;i<size;i++) {
        scanf("%d",(ptr+i));
    }
    for(i=0;i<size;i++) {
        sum=sum+*(ptr+i);
    }
    printf("'%d'",sum);
    return 0;
}
#包括
int main(){
整数大小,i,j,和=0;
认沽权(“1”);
scanf(“%d”,大小(&S);
int arr1[大小];
认沽权(“1”);
int*ptr;

对于(i=0;i取消对未初始化指针的引用是未定义的行为。正如您和您的朋友所看到的,有时这个“有效”,有时它会出现故障,而在其他一些机器上,它可能会让恶魔飞出您的鼻子(甚至在同一台机器上,它可能会在不同的运行中发生变化)。它是未定义的,结果可能是任何东西。因为“它在他的机器上工作”(很可能是堆栈使用模式的巧合,在堆栈上留下了一个半有效的内存地址供他使用)并不正确。

“未定义”并不意味着“非法”“。这只是意味着几乎任何结果都是可能的,包括看起来工作正常。如果未初始化的指针值对应于当前未使用的可写地址,或者如果缓冲区溢出溢出到未使用的内存中,则代码将愉快地运行,不会出现任何外部问题


这是UB最有害的表现形式,正是因为它看起来工作正常。它将继续正常工作,直到运行时环境发生变化,或者你在代码中做了一个不相关的更改并重新构建,然后突然所有的麻烦都消失了,你不知道为什么。我不止一次遇到过这种情况。

在启用警告的情况下,使用
gcc
编译时,编译器输出:

gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled2.c" -o "untitled2.o" 

untitled2.c: In function ‘main’:

untitled2.c:6:9: warning: unused variable ‘arr1’ [-Wunused-variable]
    6 |     int arr1[size];
      |         ^~~~

untitled2.c:3:16: warning: unused variable ‘j’ [-Wunused-variable]
    3 |     int size,i,j,sum=0;
      |                ^

untitled2.c:10:9: warning: ‘ptr’ may be used uninitialized in this function [-Wmaybe-uninitialized]
   10 |         scanf("%d",(ptr+i));
      |         ^~~~~~~~~~~~~~~~~~~

Compilation finished successfully.
因此,必须启用警告才能从编译器获取任何有用的消息

关于:

Compilation finished successfully.
当出现警告消息时,此输出仅表示编译器对代码应用了一些
变通方法,而不是生成了正确的代码

此外,关于:

int *ptr;
这将在运行时导致seg故障事件,因为它不指向程序拥有的内存

在尝试实际运行可执行文件之前,应修复上述所有问题

建议的守则如下:

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


int main( void ) 
{
    //int size,i,j,sum=0;
    int size;

    int sum=0;
    
    
    //puts( "enter1" );
    puts( "enter number integers to be summed" );
    if( scanf("%d",&size) != 1 )
    {
        fprintf( stderr, "scanf for number of integers to sum failed\n" );
        exit( EXIT_FAILURE );
    }
    
    //int arr1[size];
    puts("enter the integers, seperated by a space or newline");
    //int *ptr;
    int inputData[ size ];
    for( int i=0; i<size; i++ ) 
    {
        //scanf("%d",(ptr+i));
        if( scanf( "%d", inputData + i ) != 1 )
        {
            fprintf( stderr, "scanf for int data failed\n" );
            exit( EXIT_FAILURE );
        }   
    }
    
    for( int i=0; i<size; i++ ) 
    {
        sum += *( inputData+i );
    }
    
    printf( "'%d'", sum );
    return 0;
}


    
  • 干净地编译
  • 执行所需的功能
  • 检查并处理I/O错误
  • 现在,拟议的守则:

    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main( void ) 
    {
        //int size,i,j,sum=0;
        int size;
    
        int sum=0;
        
        
        //puts( "enter1" );
        puts( "enter number integers to be summed" );
        if( scanf("%d",&size) != 1 )
        {
            fprintf( stderr, "scanf for number of integers to sum failed\n" );
            exit( EXIT_FAILURE );
        }
        
        //int arr1[size];
        puts("enter the integers, seperated by a space or newline");
        //int *ptr;
        int inputData[ size ];
        for( int i=0; i<size; i++ ) 
        {
            //scanf("%d",(ptr+i));
            if( scanf( "%d", inputData + i ) != 1 )
            {
                fprintf( stderr, "scanf for int data failed\n" );
                exit( EXIT_FAILURE );
            }   
        }
        
        for( int i=0; i<size; i++ ) 
        {
            sum += *( inputData+i );
        }
        
        printf( "'%d'", sum );
        return 0;
    }
    
    
        
    
    #包括
    #包括
    内部主(空)
    {
    //整数大小,i,j,和=0;
    整数大小;
    整数和=0;
    //认沽权(“1”);
    puts(“输入要求和的整数”);
    如果(扫描频率(“%d”,&size)!=1)
    {
    fprintf(stderr,“scanf用于求和失败的整数数\n”);
    退出(退出失败);
    }
    //int arr1[大小];
    puts(“输入整数,用空格或换行符分隔”);
    //int*ptr;
    int输入数据[大小];
    
    对于(int i=0;当调用未定义的行为似乎起作用时,请不要感到“惊讶”。毕竟,该行为是未定义的。无论谁/无论什么人告诉您调用UB保证不起作用,他们都大错特错。未定义意味着没有定义,因此您确实无法对它将起什么作用(或不起作用)做出任何结论。因此,任务是通过严格遵守已定义的行为来编写毫无疑问的代码。好的,我会记住这一点。显然,它只是碰巧指向了一些您可以读写的有效地址。您的程序只是重写了一些它不关心的变量。如果您运气不好,您的程序将使用一些变量ram确实很关心,这会导致崩溃。“当使用未初始化的指针时,应该是UB??嗯,在他的情况下,它起作用是未定义的行为。