You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言结构体函数指针赋值类型不匹配导致段错误及打印异常

C语言结构体中函数指针使用问题排查

我编写了如下程序,用于学习函数指针及其在结构体中的用法:

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

typedef struct S_t S_t;

struct S_t {
    float *s_ptr;
    uint32_t ns;
};

typedef struct p_t p_t;

struct p_t {
    int32_t pID;
    float pVal;
};


typedef struct pr_t pr_t;

struct pr_t {
    S_t *S;
    int (*TrimS)(S_t *TS, int sSize);
    p_t *TP;
};

int ChopS(S_t *TS, int size);


float fvals[] = {0.8000000119209290, 0.2399999946355820, -0.3740000128746033, 
                0.2489999979734421, 0.9049999713897705, 0.3770000040531158, 
                -0.6959999799728394, -0.8870000243186951, -0.9739999771118164, 
                0.1410000026226044, 0.4040000140666962, 0.7779999971389771};
int arrLen = sizeof(fvals) / sizeof(fvals[0]);
float svals[20];

int ChopS(S_t *TS, int size)
{
    int i, c;
    for(i = 0; i < TS->ns; i++)
    {
        if (i >= size)
            TS->s_ptr[i] = 0.0;
    }
    c = 0;
    for(i = 0; i < TS->ns; i++)
    {
    if(TS->s_ptr[i] == 0.0)
        c++;
    }
    if (c == size)
    return 0;
    else
    return -1;
}


int main()
{
    int i, n;
    
    p_t p1 = {.pID = 1234, .pVal = 0.35};
    p_t *p2 = NULL;
    
    S_t tS1;
    S_t *tS2 = NULL;
    tS2 = malloc(sizeof(S_t));
    
    pr_t SP1;
    pr_t *SP2 = NULL;
    SP2 = malloc(sizeof(pr_t));

    p2 = (p_t *) malloc(sizeof(p_t));
    p2->pID = 1111;
    p2->pVal = 1.198;

    printf("Generating new values from original inputs as float array : \n");
    for(i = 0; i < n; i++)
    {
        svals[i] = 1 + fvals[i];
        printf("%f, ", svals[i]);
    }
    printf("\n");

    tS1.s_ptr = fvals;
    tS1.ns = arrLen;

    tS2->s_ptr = svals;
    tS2->ns = arrLen;

    SP1.S = &tS1;
    SP1.TP = &p1;
    SP1.TrimS = ChopS(&tS1, 4);
    printf("Original inputs from PR1 (Trim=%d) as %d inputs : \n", 
        SP1.TrimS, SP1.S->ns);
    for(i = 0; i < n; i++)
    {
        printf("%f, ", SP1.S->s_ptr[i]);
    }
    printf("\n");

    SP2->S = tS2;
    SP2->TP = p2;
    SP2->TrimS = ChopS(&tS2, 8);
    printf("Modified inputs from PR2 (Trim=%d) as %d inputs : \n", 
        SP2->TrimS, SP2->S->ns);
    for(i = 0; i < n; i++)
    {
        printf("%f, ", SP2->S->s_ptr[i]);
    }
    printf("\n");

    return 0;
}

初始编译警告

使用gcc编译时出现如下警告:

user@PCLT:~/Test$ gcc -std=c99 -Wall -o executetest exp.c
exp.c: In function ‘main’:
exp.c:95:15: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
    SP1.TrimS = ChopS(&tS1, 4);
            ^
exp.c:96:45: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int (*)(S_t *, int) {aka int (*)(struct S_t *, int)}’ [-Wformat=]
    printf("Original inputs from PR1 (Trim=%d) as %d inputs : \n",
                                            ~^
        *(SP1.TrimS), SP1.S->ns);
        ~
exp.c:106:24: warning: passing argument 1 of ‘ChopS’ from incompatible pointer type [-Wincompatible-pointer-types]
    SP2->TrimS = ChopS(&tS2, 8);
                        ^
exp.c:39:5: note: expected ‘S_t * {aka struct S_t *}’ but argument is of type ‘S_t ** {aka struct S_t **}’
int ChopS(S_t *TS, int size)
    ^~~~~
exp.c:106:16: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
    SP2->TrimS = ChopS(&tS2, 8);
                ^
exp.c:107:45: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int (*)(S_t *, int) {aka int (*)(struct S_t *, int)}’ [-Wformat=]
    printf("Modified inputs from PR2 (Trim=%d) as %d inputs : \n",
                                            ~^
     *(SP2->TrimS), SP2->S->ns);
     ~

初始运行异常

运行编译出的可执行文件后输出如下,触发段错误:

user@PCLT:~/Test$ ./executetest
Generating new values from original inputs as float array :
1.800000, 1.240000, 0.626000, 1.249000, 1.905000, 1.377000, 0.304000, 0.113000, 0.026000, 1.141000, 1.404000, 1.778000,
Original inputs from PR1 (Trim=-1) as 12 inputs :
0.800000, 0.240000, -0.374000, 0.249000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
Segmentation fault (core dumped)

其中非指针类型的pr_t变量SP1运行结果符合预期,但指针类型的pr_t变量SP2运行异常。


首次修改后的新问题

根据建议修改代码:

  • 将原代码第95行替换为:
SP1.TrimS = ChopS;
SP1.TrimS(&tS1, 4);
  • 将原代码第106行替换为:
SP2->TrimS = ChopS;
SP2->TrimS(tS2, 8);

修改后程序不再触发段错误,但打印Trim值时输出为(Trim=94135985899402)这类大数字,不符合预期的(Trim=0)状态码。


错误原因说明

代码中一共存在4个核心问题:

  1. 函数指针赋值逻辑错误
    TrimS是函数指针类型,存储的是函数的入口地址。直接写ChopS(&tS1, 4)是调用ChopS函数,会把函数返回的int类型结果赋值给函数指针,触发类型不匹配警告。正确的赋值方式是直接传入函数名:SP1.TrimS = ChopS;,需要执行裁剪逻辑时再通过函数指针传参调用。

  2. 参数类型不匹配
    tS2本身就是S_t*类型,传入&tS2会得到S_t**类型的二级指针,和ChopS函数要求的S_t*参数类型不符,触发指针类型不兼容警告。调用时直接传入tS2即可。

  3. 未初始化变量导致越界
    代码中定义了循环变量n但从未赋值,n是栈上的随机值。如果n的值大于数组实际长度,循环访问数组时就会越界访问非法内存,这是段错误的核心原因。这里n应该在循环前赋值为arrLen。

  4. 打印对象错误导致输出异常数字
    修改后直接打印SP1.TrimS,实际打印的是函数指针存储的函数入口内存地址,所以会输出无意义的大数字。如果需要获取裁剪操作的返回状态码,需要定义int类型变量接收函数调用的返回值,再打印这个变量:

int trim_ret1 = SP1.TrimS(&tS1, 4);
// 后续printf中打印trim_ret1即可

内容的提问来源于stack exchange,提问作者skrowten_hermit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:03:16