In the following C program, there are different input parameters.
One of those parameters, -f
is to especify the filename of the results
#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);
}
I have compiled with
gcc -c abr1.c -Wall
gcc abr1.o -o abr1
but when I run the program
./abr1 -f "result01.res"
zsh: bus error ./abr1 -f "result01.res"
How I can pass the filename to this C program?
CodePudding user response:
This is a problem:
fname = (char *)malloc(200*sizeof(char));
fname = "abr.res";
You malloc
space that fname
points at, then in the next line tell fname
to point at the string literal "abr.res". That creates a memory leak, since you now have nothing pointing to your malloc
ed memory.
Furthermore, with the f
option, you use strcpy
to write to fname
. Modifying a string literal is Undefined Behavior, and could certainly explain the behavior you're seeing.
Instead, I recommend
char fname[200] = "abr.res";
This creates fname
as a writable memory area of 200 bytes long, initializes it with "abr.res"
as a default value, and doesn't deal with manual memory management.
Per @Laci 's comment, you're vulnerable to a buffer overflow blindly copying user input from the command line to your buffer. Steps should be taken to eliminate that risk. One way is to use 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] = '\0';
break;