zsh:传递结果文件名编译 C 程序时出现总线错误

zsh: bus error when passing results filename to compile C program

在下面的C程序中,有不同的输入参数。 这些参数之一,-f 是指定结果的文件名

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

#define SOURCES 4
#define NUM_T 1000

char *prgname;
char usage[]="%s [-uUdipT] -f filename\n";

int main(int argc, char *argv[])
{
    FILE *filefd;
    char *fname;
    int  lt;            /* lower threshold */
    int  ut;            /* upper threshold */
    int  T;             /* Actualization time (cells) */
    double RDF, RIF;        /* Rate Decrease-Increate Factor */
    double PCR;         /* Peak Cell Rate */
    int qlen;           /* queue length */
    int bitEFCI[SOURCES];   /* EFCI bit */
    double ACR [SOURCES];   /* Allowed Cell Rate */
    double mean[SOURCES];   /* Mean Cell Rate */
    int i, t;           /* control variables */
    double ACRacc;

    prgname = strrchr(argv[0], '/');
    if (prgname == (char *)NULL) prgname = argv[0];
    else prgname++; 
    
    /********************************************/
    /* DEFAULT VALUES & INICIALIZATION          */
    /********************************************/
    
    fname = (char *)malloc(200*sizeof(char));
    fname = "abr.res";
    ut = 550;
    lt = 450;
    RDF = 0.4;
    RIF = 0.02;
    PCR = 150E6;
    T = 70;
    qlen = 0;

    for (i=0; i < SOURCES; i++)
    {bitEFCI[i] = 0; ACR[i] = 0.0; mean[i] = 0.0;}

    /********************************************/
    /* USER COMMAND LINE VALUES                 */
    /********************************************/
    
    while (1)
    {
    int c;

    c = getopt(argc, argv, "u:U:d:i:p:T:f:h");
    if (c == EOF) break;

    switch (c)
    {
        case 'h': printf(usage, prgname);
                fputs("-h\tHelp\n", stdout);
                fputs("-u\tLower threshold (cells)\n", stdout);
                fputs("-U\tUpper threshold (cells)\n", stdout);
                fputs("-d\tDecrement factor\n", stdout);
                fputs("-i\tIncrement factor\n", stdout);
                fputs("-p\tPeak cell rate (Mbps)\n", stdout);
                fputs("-T\tActualization period (cells)\n", stdout);
                fputs("-f\tResults file name\n", stdout);
                exit(0);
        case 'u': lt = atoi(optarg);
                break;
        case 'U': ut = atoi(optarg);
                break;
        case 'd': RDF = atof(optarg);
                break;
        case 'i': RIF = atof(optarg);
                break;
        case 'p': PCR = atof(optarg);
                break;
        case 'T': T = atoi(optarg);
                break;
        case 'f': strcpy(fname, optarg);
                break;
        default : fprintf(stderr, usage, prgname); exit(1);
    }
    }
    
    if ((filefd = fopen(fname, "w")) == NULL)
    {perror("fopen"); exit(1);}

    /********************************************/
    /* MAIN LOOP                                */
    /********************************************/
    
    for (t = 1; t<= NUM_T; t++)
    {
    ACRacc = 0.0;
    fprintf(filefd, "%d\t", t);
    for (i=0; i < SOURCES; i++)
    {
        if (bitEFCI[i] == 0)
             ACR[i] = (ACR[i]+PCR*RIF>PCR)?(PCR):(ACR[i]+PCR*RIF);
        else ACR[i] *= RDF;

        mean[i] += (ACR[i]-mean[i])/(double)t;
        ACRacc  += ACR[i];
        fprintf(filefd, "%4.1f\t%4.1f\t", ACR[i]/1E6, mean[i]/1E6);
    }
        
    qlen += (int)(ACRacc*T*424/PCR);
    qlen  = (qlen<=T*424)?(0):(qlen - T*424);
    fprintf(filefd, "%d\n", qlen/424);
        
    for (i=0; i < SOURCES; i++)
    {
        if (qlen >= ut*424) bitEFCI[i] = 1;
        else if (qlen < lt*424) bitEFCI[i] = 0;
    }
    fflush(filefd);
    }   

    fclose(filefd);
    exit(0);
}

我用

编译了
gcc -c abr1.c -Wall
gcc abr1.o -o abr1

但是当我运行程序

./abr1 -f "result01.res"
zsh: bus error  ./abr1 -f "result01.res"

如何将文件名传递给此 C 程序?

这是一个问题:

fname = (char *)malloc(200*sizeof(char));
fname = "abr.res";

malloc space fname 指向,然后在下一行告诉 fname 指向字符串文字“abr.res”。这会造成内存泄漏,因为您现在没有任何东西指向您的 malloced 内存。

此外,使用 f 选项,您可以使用 strcpy 写入 fnameModifying a string literal is Undefined Behavior,当然可以解释您所看到的行为。

相反,我推荐

char fname[200] = "abr.res";

这将创建fname作为200字节长的可写内存区域,并使用"abr.res"作为默认值对其进行初始化,并且不处理手动内存管理。

根据@Laci 的评论,您很容易受到缓冲区溢出的影响,盲目地将用户输入从命令行复制到您的缓冲区。应采取措施消除这种风险。一种方法是使用 strncpy:

case 'f':
  strncpy(fname, optarg, sizeof fname);
  // one of the dangers of strncpy is it is NOT guaranteed to NUL
  // terminate the string, so do that manually just in case
  fname[sizeof(fname)-1] = '[=12=]';
  break;