"recommended way to store the same type of values in C. I could not find the answer,..."
Without knowing more about your immediate purpose/plans, the question does not have a right answer, only guesses. Following are some guiding suggestions based on scope of project assumptions.
Header file defined constants:
If this is a quick prototype or proof of concept, then using the header file approach is likely to be completely adequate. This probably depends on how large the “…large amount of constant values…” actually is. It’s all really up to you. Depending on how patient you are about editing all those values, and how meticulous you are when accuracy of value is important. If just 10-20 items, then okay, If much larger than that, I would choose to nix the header file idea and use either a configuration file, or database entry.
Disadvantage - This is not run-time adjustable. What is defined at compile time is the behavior you will get at run-time.
Advantage – simple to implement. (Using #defines, extern scoped variables, and macro definitions is easy and well documented)
External initialization file/database:
If project is well defined, and fairly well along in development, and uses a large number of configuration values, then reading from external storage (whether it be file or database.) is probably best. Once implemented this will supports maximum run-time flexibility with minimal effort.
Disadvantage – This requires more time and rigor during implementation. The code to read in a file does not have to be complicated as long as the file is syntactically strict, and does not require frequent changes to field definitions, or count of fields.
Advantage – Maximum run-time flexibility. Can use run-time prompting of user to input which file/database table to use during run-time session, etc.
Below is a very simple concept for reading a simple file (such as the one your post describes) Even though this will compile and build, treat it as pseudo code and modify/expand as needs dictate.
enum {//enum values useful to use as indexes to struct values during initialization
IP,
SAMPS_PER_SCAN,
SCAN_FREQUENCY,
USE_FILTER,
MEMBERS_MAX
};
//Useful during file read to test record field name
//against coded field strings prior to parsing field
//data value into struct
const char members[][20] = {"IP","SCAN_FREQUENCY","SCAN_FREQUENCY","USE_FILTER"};
int get_member_index(const char *mem);//prototype helper function
typedef struct {//struct designed to match configuration dataset
char ipAddr[20];
int sPerScan;
double sfreq;
bool filter;
}params_s;
params_s params;//create instance of struct parameters
int main(void)
{
int index = 0;
char line[80] = {0}; //change size bases on known actual file contents
char *tok = NULL;
FILE *fp = fopen(".\\data.txt", "r");
if(fp)
{
while(fgets(line, sizeof(line), fp))
{
//This is where file is parse
index = get_member_index(line);
if(index < 0)
{
//error message to user that file is corrupt or incorrect
//exit program, or provide try again loop to enter another file name
}
else
{
switch(index) {//parse data according to type of each parameter
case IP:
//use strtok or scanf strchr combination to extract value from string
tok = strtok(line, "=\" ");//consume first part of line
tok = strtok(NULL, "=\" ");
strcpy(params.ipAddr, tok);
break;
case SAMPS_PER_SCAN:
tok = strtok(line, "= ");//consume first part of line
tok = strtok(NULL, "= ");//get value
params.sPerScan = atoi(tok);
break;
case SCAN_FREQUENCY:
//construt parse for double
break;
case USE_FILTER:
//construct parse for bool
break;
};
}
}
fclose(fp);//file no longer needed, close it
//use captured struct parameter data throughout code
//via passing as function argument.
}
return 0;
}
//helper function to get index of parameter in data line
int get_member_index(const char *mem)
{
for(int i=0;i<MEMBERS_MAX; i++)
{
if(strstr(mem, members[i]))
{
return i;
}
}
return -1;
}