一个关于C语言指针的问题

请教一个关于Segmentation fault的问题 大学刚学C语言 怎么都想不出原因
有两段程序 均为书上的题目 其中一段代码如下:

#include"stdio.h"
#define N 5
void main()
{
    float *get_arry();
    float array_sum(float *,int);
    float array_avg(float *,int);
    float *arry;
    arry=get_arry();
    printf("the sum of the array is %f\n",array_sum(arry,N));
    printf("the average of the array is %f\n",array_avg(arry,N));
}

float *get_arry()
{
    int i;
    float num,*arry;
    for(i=0;i<N;i++)
    {
        printf("please input a number\n");
        scanf("%f",&num);
        *(arry+i)=num;
    }
    return arry;   
}

float array_sum(float *arry,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum+=*(arry+i);
    }
    return sum;
}

float array_avg(float *arry,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum+=*(arry+i);
    }
    return sum/n;
}

程序就是要求编写函数算平均数和总和 但在运行中 当输入第一个数字后 在float get_arry()函数的(arry+i)=num;处会出现Segmentation fault错误
类似的还有一段程序 为哥德巴赫猜想 程序中的int *prime(int)中关于指针的赋值方式与前一个并没有什么区别 但此程序运行正确 请帮我分析一下 实在是想不出来

#include"stdio.h"
int k;
void main()
{
    void get_prime(int *,int);
    int *prime(int);
    int a,*b,i;
    printf("please input a even number(>6):\n");
    scanf("%d",&a);
    if(a<=6||a%2!=0)
    {
        printf("the number is illegal!");
    }
    b=prime(a);
    for(i=0;i<k;i++)
    {
        printf("%d\t",*(b+i));
    }
    get_prime(b,a);
}

int *prime(int a)
{
    int *num,i,j;
    k=0;
    for(i=2;i<a;i++)
    {
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                break;
            }
        }
        if(j==i)
        {
            *(num+k)=j;
            k++;    
        }
    }
    return num;
}

void get_prime(int *a,int number)
{
    int i;int j;
    for(i=0;i<k;i++)
    {
        for(j=0;j<k;j++)
        {
            if(a[j]+a[i]==number)
            {
                printf("%d+%d=%d",a[i],a[j],number);
                return;
            }
        }
    }
}

float num,*arry;
这个没有分配内存
应该是
float num,*arry;
arry = (float *)malloc(sizeof(float) * N);
完整程序是

#include"stdio.h"
#include"stdlib.h"

#define N 5
float *get_arry();
float array_sum(float *,int);
float array_avg(float *,int);
    
int main()
{
    float *arry;
    arry=get_arry();
    printf("the sum of the array is %f\n",array_sum(arry,N));
    printf("the average of the array is %f\n",array_avg(arry,N));
}
 
float *get_arry()
{
    int i;
    float num,*arry;
    arry = (float *)malloc(sizeof(float) * N);
    for(i=0;i<N;i++)
    {
        printf("please input a number\n");
        scanf("%f",&num);
        *(arry+i)=num;
    }
    return arry;   
}
 
float array_sum(float *arry,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum+=*(arry+i);
    }
    return sum;
}
 
float array_avg(float *arry,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum+=*(arry+i);
    }
    return sum/n;
}

下一个程序也是类似问题,正确写法:

#include"stdio.h"
#include"stdlib.h"
int k;
int main()
{
    void get_prime(int *,int);
    int *prime(int);
    int a,*b,i;
    printf("please input a even number(>6):\n");
    scanf("%d",&a);
    if(a<=6||a%2!=0)
    {
        printf("the number is illegal!");
    }
    b=prime(a);
    for(i=0;i<k;i++)
    {
        printf("%d\t",*(b+i));
    }
    get_prime(b,a);
}
 
int *prime(int a)
{
    int *num,i,j;
    num = (int *)malloc(sizeof(int) * a);
    k=0;
    for(i=2;i<a;i++)
    {
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                break;
            }
        }
        if(j==i)
        {
            *(num+k)=j;
            k++;    
        }
    }
    return num;
}
 
void get_prime(int *a,int number)
{
    int i;int j;
    for(i=0;i<k;i++)
    {
        for(j=0;j<k;j++)
        {
            if(a[j]+a[i]==number)
            {
                printf("%d+%d=%d",a[i],a[j],number);
                return;
            }
        }
    }
}

唉,你这个没有分配内存啊,当然会出错了

修复后的代码

#include <stdio.h>
#include <stdlib.h> // 添加此头文件

#define N 5

float *get_arry();
float array_sum(float *, int);
float array_avg(float *, int);

void main()
{
    float *arry;
    arry = get_arry();
    printf("the sum of the array is %f\n", array_sum(arry, N));
    printf("the average of the array is %f\n", array_avg(arry, N));

    // 在程序结束前释放动态分配的内存
    free(arry);
}

float *get_arry()
{
    int i;
    float num, *arry;

    // 分配内存
    arry = (float *)malloc(N * sizeof(float));
    if (arry == NULL) {
        printf("Memory allocation failed\n");
        exit(1); // 退出程序
    }

    for (i = 0; i < N; i++)
    {
        printf("please input a number\n");
        scanf("%f", &num);
        *(arry + i) = num;
    }
    return arry;
}

// 其他函数不变


这两种写法都是错误的,只不过是一个压根没有申请内存就写直接报错了(情况一),而第二个是写了临时变量的地址,没有即时报错,而且可能也运行出来了结果,但同样是致命的,写了未申请的内存,可能会导致不可预知的奇怪后果。

参考gpt:
结合自己分析给你如下建议:
Segmentation fault(段错误)是一种常见的程序运行错误,通常是由于程序试图访问非法的内存地址导致的。例如,访问空指针、野指针、越界的数组或指针、已经释放的内存等等。当操作系统检测到这种非法访问时,就会向程序发送SIGSEGV信号,终止程序的运行,并可能生成core dump文件。
在您提供的两段程序中,我发现了一些可能导致段错误的问题:
在第一段程序中,您定义了一个float类型的指针arry,但是没有为它分配任何内存空间。当您试图在get_arry函数中给它赋值时,就会发生段错误,因为您试图访问一个未知的内存地址。为了解决这个问题,您需要在get_arry函数中使用malloc或者new为arry分配足够的内存空间,例如:

float *get_arry()
{
    int i;
    float num,*arry;
    // 为arry分配N个float类型的内存空间
    arry = (float *)malloc(sizeof(float) * N);
    for(i=0;i<N;i++)
    {
        printf("please input a number\n");
        scanf("%f",&num);
        *(arry+i)=num;
    }
    return arry;   
}

在第二段程序中,您也定义了一个int类型的指针num,但是也没有为它分配任何内存空间。当您试图在prime函数中给它赋值时,也可能发生段错误。为了解决这个问题,您也需要在prime函数中使用malloc或者new为num分配足够的内存空间,例如:

int *prime(int a)
{
    int *num,i,j;
    // 为num分配a个int类型的内存空间
    num = (int *)malloc(sizeof(int) * a);
    k=0;
    for(i=2;i<a;i++)
    {
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                break;
            }
        }
        if(j==i)
        {
            *(num+k)=j;
            k++;    
        }
    }
    return num;
}

#include <stdio.h>
#include <stdlib.h> // 添加此头文件
#define N 5
float *get_arry();
float array_sum(float *, int);
float array_avg(float *, int);
void main()
{
    float *arry;
    arry = get_arry();
    printf("the sum of the array is %f\n", array_sum(arry, N));
    printf("the average of the array is %f\n", array_avg(arry, N));
    // 在程序结束前释放动态分配的内存
    free(arry);
}
float *get_arry()
{
    int i;
    float num, *arry;
    // 分配内存
    arry = (float *)malloc(N * sizeof(float));
    if (arry == NULL) {
        printf("Memory allocation failed\n");
        exit(1); // 退出程序
    }
    for (i = 0; i < N; i++)
    {
        printf("please input a number\n");
        scanf("%f", &num);
        *(arry + i) = num;
    }
    return arry;
}
// 其他函数不变

引用chatgpt内容作答:
在你的两段代码片段中,你遇到的问题与未初始化的指针有关。当你声明一个指针变量时,它并不会自动指向有效的内存。在使用之前,你需要为它指向的数据分配内存空间。这就是为什么你会遇到“Segmentation fault(分段错误)”。

让我们分析一下这两个代码片段中的问题:

第一个代码片段:

float *get_arry()
{
    int i;
    float num,*arry; // 'arry' 是一个未初始化的指针
    for(i=0;i<N;i++)
    {
        printf("请输入一个数字\n");
        scanf("%f",&num);
        *(arry+i)=num; // 尝试向一个未初始化的指针写入数据
    }
    return arry;   
}

在这个函数中,你声明了一个指针 float *arry,但在向其写入数据之前,你没有为它分配内存。这将导致分段错误,因为你尝试写入一个未知的内存位置。要解决这个问题,你应该在写入数据之前使用 malloc() 为数组分配内存。以下是修正后的版本:

float *get_arry()
{
    int i;
    float num, *arry;
    arry = (float *)malloc(N * sizeof(float)); // 分配内存
    if (arry == NULL) {
        // 处理内存分配错误
        printf("内存分配失败\n");
        exit(1);
    }
    for (i = 0; i < N; i++)
    {
        printf("请输入一个数字\n");
        scanf("%f", &num);
        *(arry + i) = num;
    }
    return arry;
}

记得在主函数中使用完 arry 后使用 free(arry),以避免内存泄漏。

第二个代码片段:

int *prime(int a)
{
    int *num, i, j; // 'num' 是一个未初始化的指针
    k = 0;
    for (i = 2; i < a; i++)
    {
        for (j = 2; j < i; j++)
        {
            if (i % j == 0)
            {
                break;
            }
        }
        if (j == i)
        {
            *(num + k) = j; // 尝试向一个未初始化的指针写入数据
            k++;
        }
    }
    return num;
}

在这里同样,你声明了一个指针 int *num,但在向其写入数据之前,你没有为它分配内存。你需要类似之前的方法,使用 malloc() 来为它分配内存。

int *prime(int a)
{
    int *num, i, j;
    num = (int *)malloc(a * sizeof(int)); // 分配内存
    if (num == NULL) {
        // 处理内存分配错误
        printf("内存分配失败\n");
        exit(1);
    }
    k = 0;
    for (i = 2; i < a; i++)
    {
        for (j = 2; j < i; j++)
        {
            if (i % j == 0)
            {
                break;
            }
        }
        if (j == i)
        {
            *(num + k) = j;
            k++;
        }
    }
    return num;
}

同样,在使用完 num 后,记得使用 free(num),以避免内存泄漏。

在这两种情况下,分段错误的原因是你尝试向未分配内存的位置写入数据。始终确保使用 malloc() 为指针分配内存,并在使用完毕后释放它,以避免内存问题。

第一段

#include"stdio.h"
#include <stdlib.h>
#define N 5

float *get_arry()
{
    int i;
    float num,*arry;
    arry = (float *)malloc(sizeof(float) * N); // 分配N个浮点数大小的内存空间
    for(i=0;i<N;i++)
    {
        printf("please input a number\n");
        scanf("%f",&num);
        *(arry+i)=num;
    }
    return arry;   
}

float array_sum(float *arry,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum+=*(arry+i);
    }
    return sum;
}

float array_avg(float *arry,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum+=*(arry+i);
    }
    return sum/n;
}

int main()
{
    
    float array_sum(float *,int);
    float array_avg(float *,int);
    float *arry;
    
    // 释放arry指向的内存空间
    // free(arry);

    // 重新分配内存空间
    arry=get_arry();
    printf("the sum of the array is %f\n",array_sum(arry,N));
    printf("the average of the array is %f\n",array_avg(arry,N));
}

第二段

#include"stdio.h"
#include <stdlib.h>
#define N 5

int k;

int *prime(int a)
{
    int *num,i,j;
    k=0;
    num = (int *)malloc(sizeof(int) * a); // 分配a个整数大小的内存空间
    for(i=2;i<a;i++)
    {
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                break;
            }
        }
        if(j==i)
        {
            *(num+k)=j;
            k++;    
        }
    }
    return num;
}

void get_prime(int *a,int number)
{
    int i;int j;
    for(i=0;i<k;i++)
    {
        for(j=0;j<k;j++)
        {
            if(a[j]+a[i]==number)
            {
                printf("%d+%d=%d",a[i],a[j],number);
                return;
            }
        }
    }
}

int main()
{
    
    void get_prime(int *,int);
    int *prime(int);
    int a,*b,i;
    printf("please input a even number(>6):\n");
    scanf("%d",&a);
    if(a<=6||a%2!=0)
    {
        printf("the number is illegal!");
    }
    b=prime(a);
    for(i=0;i<k;i++)
    {
        printf("%d\t",*(b+i));
    }
    get_prime(b,a);
    free(b); // 释放b指向的内存空间
}


在第一个程序中,您遇到Segmentation fault错误的问题是因为您在get_arry()函数中使用了一个未初始化的指针arry来存储输入的数据。在C语言中,指针在使用前必须被正确地分配内存,否则会导致未定义行为,如Segmentation fault错误。

您可以通过以下方式修复这个问题:

float *get_arry()
{
    int i;
    float num, *arry;

    arry = (float *)malloc(N * sizeof(float)); // Allocate memory for the array

    if (arry == NULL)
    {
        printf("Memory allocation failed\n");
        exit(1);
    }

    for (i = 0; i < N; i++)
    {
        printf("please input a number\n");
        scanf("%f", &num);
        *(arry + i) = num;
    }
    return arry;
}

在这里,我们使用malloc函数为arry分配了足够的内存来存储N个浮点数,然后在使用前进行了正确的内存分配。

对于第二个程序,您在prime函数中同样遇到了未初始化指针num的问题,但程序仍然能够工作的原因是运气。未初始化指针可能会指向一块随机的内存,有时候会恰好是可访问的,导致程序看起来能够正常工作。然而,这种行为是不可靠且不安全的。为了确保程序的稳定性和可靠性,您应该始终正确地分配和初始化指针所指向的内存。

在第二个程序中,您可以使用类似的方法来为num分配内存:

int *prime(int a)
{
    int *num, i, j;

    num = (int *)malloc(a * sizeof(int)); // Allocate memory for the array

    if (num == NULL)
    {
        printf("Memory allocation failed\n");
        exit(1);
    }

    k = 0;
    for (i = 2; i < a; i++)
    {
        for (j = 2; j < i; j++)
        {
            if (i % j == 0)
            {
                break;
            }
        }
        if (j == i)
        {
            *(num + k) = j;
            k++;
        }
    }
    return num;
}

同样地,使用malloc来为指针分配足够的内存,确保程序的稳定性。

没有申请内存使用,当然会Segmentation fault了

没分配内存

【以下回答由 GPT 生成】

问题分析:

在函数get_array()中,出现了Segmentation fault错误。错误的原因是指针array没有被正确初始化,没有指向一个合法的内存地址。在函数中使用指针之前,需要先为其分配内存空间。

解决方案:

正确初始化指针array,为其分配内存空间。可以使用malloc函数在堆内存上动态分配内存空间。

修改后的代码如下:

#include<stdio.h>
#include<stdlib.h> // 包含头文件

#define N 5

void main()
{
    float *get_array();
    float array_sum(float *,int);
    float array_avg(float *,int);
    float *array;
    array = get_array();
    printf("the sum of the array is %f\n",array_sum(array,N));
    printf("the average of the array is %f\n",array_avg(array,N));
}

float *get_array()
{
    int i;
    float num,*array;
    array = (float *)malloc(N * sizeof(float)); // 分配内存空间
    for(i=0;i<N;i++)
    {
        printf("please input a number\n");
        scanf("%f",&num);
        *(array+i) = num;
    }
    return array;   
}

float array_sum(float *array,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum += *(array+i);
    }
    return sum;
}

float array_avg(float *array,int n)
{
    int i;
    float sum;
    sum=0;
    for(i=0;i<n;i++)
    {
        sum += *(array+i);
    }
    return sum/n;
}

请注意,使用完动态分配的内存后,需要使用free函数释放内存,避免内存泄漏。

希望这个解决方案对您有所帮助。如果您有任何疑问,请随时向我提问。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

第一段代码:由于在get_arry函数中访问了未初始化的内存空间。在get_arry函数中,您没有为arry数组分配内存。需要将float *arry声明为float arry[N],这样就可以为数组分配内存,并使用array[i] = num来设置数组的值。


第二段代码:因为prime()函数只是计算并返回一个数组,而不是直接操作内存。在main()函数中,prime()函数的返回值被赋值给了一个指针b,然后通过b来访问数组。get_prime()函数中,prime()函数的返回值被用于遍历数组,寻找满足条件的数对。

在你的第一个代码段中,出现 Segmentation fault 的问题是因为你在 float *get_arry() 函数中使用了一个未初始化的指针 arry 来存储输入的数据。这导致在赋值 *(arry+i)=num; 时访问了未知的内存位置,从而触发了 Segmentation fault 错误。

解决这个问题的方法是在 get_arry 函数内部为指针 arry 分配内存空间,例如使用动态内存分配函数 malloc。你可以像这样修改你的代码:

float *get_arry()
{
    int i;
    float num, *arry;
    arry = (float *)malloc(N * sizeof(float)); // Allocate memory
    if (arry == NULL)
    {
        printf("Memory allocation failed.\n");
        exit(1); // Exit if memory allocation fails
    }
    
    for(i = 0; i < N; i++)
    {
        printf("please input a number\n");
        scanf("%f", &num);
        *(arry + i) = num;
    }
    return arry;   
}

在你的第二个代码段中,虽然也使用了指针 num,但你没有直接在其中存储数据,而是在 prime 函数内部根据条件将数据存储到 *(num + k) 中。因此,prime 函数不会出现和上一个代码段中的错误一样的问题。

记得在程序结束时,使用 free 函数释放动态分配的内存,以防止内存泄漏。

这两段代码都存在潜在的问题,我将分别对它们进行分析。

第一段代码的问题:

1、在get_arry函数中,你声明了一个指向浮点数的指针arry,但没有给它分配内存。然后你尝试将数值分配给arry+i,这会导致段错误,因为arry指针没有指向有效的内存地址。
2、在主函数中,你声明了一个指向浮点数的指针arry,但是你没有给它分配内存,而是直接将它传递给了get_arry函数。在get_arry函数中,你为这个指针分配了内存,但是你没有将这个内存的指针返回给主函数。这会导致主函数中的arry指针依然是一个未初始化的指针,所以你在后续使用它时会出现段错误。

你可以修改代码如下:

#include <stdio.h>  
#include <stdlib.h>  
  
#define N 5  
  
float *get_arry() {  
    int i;  
    float *arry = (float *) malloc(N * sizeof(float)); // 分配内存  
    for (i = 0; i < N; i++) {  
        printf("请输入一个数字:\n");  
        scanf("%f", &arry[i]); // 将数组名替换为 arry 指针,可以直接使用索引访问元素  
    }  
    return arry;     
}  
  
int main() {  
    float *arry;  
    arry = get_arry(); // 获取内存地址  
    printf("数组的总和是:%f\n", array_sum(arry, N));  
    printf("数组的平均值是:%f\n", array_avg(arry, N));  
    free(arry); // 释放内存  
    return 0;  
}

第二段代码的问题:

1、prime函数内部没有为num分配内存。num是一个指向整数的指针,但在函数内部你没有为它分配内存。这会导致在get_prime函数中访问非法内存地址。
2、k变量在函数内部被改变,但是在主函数中调用时,它已经被修改为其他值,这可能导致打印不完整的结果或者错误的结果。

你可以修改代码如下:

#include <stdio.h>  
#include <stdlib.h>  
  
int k = 0; // 全局变量 k  
  
int *prime(int a) {  
    int *num = (int *) malloc((a / 2) * sizeof(int)); // 分配内存  
    int i, j;  
    for (i = 2; i < a; i++) {  
        for (j = 2; j < i; j++) {  
            if (i % j == 0) {  
                break;  
            }  
        }  
        if (j == i) {  
            num[k] = i; // 将数组名替换为 num 指针,可以直接使用索引访问元素  
            k++;      
        }  
    }  
    return num; // 注意不要改变 k 的值,因为它在主函数中被使用  
}  
  
void get_prime(int *a, int number) {  
    int i, j;  
    for (i = 0; i < k; i++) { // 在这里直接使用全局变量 k 是安全的,因为它是只读的,不会被函数改变值。但是注意,如果你的函数需要改变它,你需要在函数内部再次传递它。  
        for (j = 0; j < k; j++) { // 这里再次使用 k 是安全的,因为它是只读的。  
            if (a[j] + a[i] == number) { // 注意这里直接使用了数组名,而不是数组指针。因为数组名本质上就是一个指向数组第一个元素的指针。  
                printf("%d + %d = %d\n", a[i], a[j], number); // 添加换行符使输出更清晰。  
                return; // 在找到第一个配对后立即返回。如果你想找到所有配对,你需要删除 return 语句或者将结果存储在一个列表中并返回。  
            }  
        }  
    }  
}  
  
int main() {  
    int a, number;  
    printf("请输入一个偶数(>6):\n");  
    scanf("%d", &a); // 注意使用 & 操作符获取变量的地址。scanf 需要这个地址来将输入的值存储到变量中。  
    if (a <= 6 || a % 2 != 0) { // 这里需要使用 || 逻辑

C语言指针详解(经典,非常详细)
可以学习,理解下
https://blog.csdn.net/u013728021/article/details/91451573

你需要知道变量的作用域函数的参数传递,第一个程序函数里定义的指针,不能正确的将你想要的数据传到函数外,第二个程序的int变量,是一个值传递,可以传递数据