Best ways of retrieving strings based on parsed integer code? - c

Please ignore the topic of the post as it may sound something else instead of what I am actually asking here.
I want to make a C function which should retrieve me a string value associated with a specific integer code whose signature will be something very simple like:
char *Get_Msg (int code, char *errorInfoTable[][2]);
So, I need the strings as well associated codes stored first and because I cannot take an array of multiple datatypes, I end up storing the codes also in terms of strings as:
char *errorInfo[][2] = {
/* Error Code Error Message
* ---------- ------------- */
{ "0", "No error" },
{ "93", "Error in processing" },
{ "-32700", "PARSE_ERROR" },
{ "-32600", "INVALID_REQUEST " },
};
Then I may just read this table in the function which in turn should return me the associated string. Firstly, is it a good way to define this table inside that function itself or as a global variable in the file. But what if I wish to store this functionality in a separate C file and call it from some other file. I see that if I declare the file as a global variable, I need to declare an extern for char *errorInfoTable[][2] in the main file and the function and then parse in the function. I want the code to calculate the number of rows in the parsed table itself. This does not seem to work if I try to calculate the number of rows withing the Get_Msg function as the function cannot see it from the formal parameter char *errorInfoTable[][2]. I can do this by mentioning the number of rows in the formal parameter or passing the number of rows as well in the function but I don't want to calculate the number of rows explicitly anywhere. I want to design it in such a way that the programmer will just add/delete the number of rows in the table and should not touch any dimensions anywhere else in the program.
Is there any other way you to store and retrieve strings from this table? or any other better ways for this functionality?

struct { int error_code; const char *message; } errorInfo[] = {
/* Error Code Error Message
* ---------- ------------- */
{ -32700, "PARSE_ERROR" },
{ -32600, "INVALID_REQUEST " },
{ 0, "No error" },
{ 93, "Error in processing" },
};
That should give you what you want. And keeping it sorted can even allow you to do logarithmic lookup.
I'd also keep the table static and inside Get_Msg.
If you need to store more data relating to the code, you would do something like this:
struct error_code_data {
int error_code;
const char *message;
/* More data */
};
struct error_code_data const * get_error_code_data(int error_code);

Related

Define error messages in header or in function in c

If I have a bunch of error codes in my application header.h like:
enum errors {
ERROR_NONE,
ERROR_TOTO,
ERROR_TATA,
ERROR_TUTU,
ERROR_MAX,
};
Should I define the string associated with each code in the header like this:
static const char * const errors_strings[ERROR_MAX] = {
"ERROR_NONE",
"Something happened with toto",
"Tata is wrong",
"Pasta or pizza?",
};
or directly in the printing function:
void print_error(int error)
{
char* array[ERROR_MAX] = {
"ERROR_NONE",
"Something happened with toto",
"Tata is wrong",
"Pasta or pizza?"
};
printf("%s\n", errors_strings[error]);
}
Which is the better practice?
First of all, make the error enum a named type with typedef. Ideally we shouldn't mix int and enum types but treat enum as distinct types, even though the weak type system in C doesn't provide much help there. (However, check out How to create type safe enums? for some tips & tricks.)
As for if you should have the string table outside a function or inside one, it entirely depends on if one or several functions are using it. If only one function is using it, then it's a good idea to place the table inside it, to reduce its scope.
Also since the string array has size ERROR_MAX it cannot hold more initialized items than that, but nothing prevents it from having less. Therefore to guarantee integrity between the enum and the table, always do this:
static const char * const errors_strings[] = { ... }; // no size specified
_Static_assert(sizeof errors_strings / sizeof *errors_strings == ERROR_MAX,
"helpful error message here");

When to specify function type in C?

I have just started learning C Programming and while trying to do a couple of example exercises, I found myself confused as to when is the best scenario to specify the function type.
I apologize in advance if my title is misleading.
One such example is getting the dollars (number of notes) where I am suppose to print out the results.
While I have it working, I am using void but while looking online, it seems that int function should be used instead?
I have 2 questions:
Initially I have my printf statement under void, in general coding, should such print statements be placed there or should it be in main()?
As mentioned above, using this case example of mine, is it a right/ wrong to use void?
My code is as follows:
#include <stdio.h>
void dollars_calculation(int *input_amt, int dollars_value)
{
int change_result = 0;
change_result = (*input_amt / dollars_value);
printf("Number of %3d-dollars:\t%d pcs\n", dollars_value, change_result);
if (change_result)
{
*input_amt = (*input_amt - (dollars_value * change_result));
}
}
int main()
{
int input_amt = 0;
int counter = 0;
int dollars_arr[3] = {100, 50, 10};
printf("Input amount: ");
scanf("%d", &input_amt);
for (counter=0; counter<3; counter++)
{
// Check for the number of denomiations required.
dollars_calculation(&input_amt, dollars_arr[counter]);
}
}
The "function type" as you call it is actually the data type that you might want the function to return.
For example your dollars_calculation function could return an int, which is the result of your calculation, rather than using the pointer value to set an external variable.
Alternatively, you may be want a value returned that can be used to indicate success or failure of a function. This need not be a Boolean value, but could be an integer or even an enumerated type.
In general you want to write functions so that they are fully re-entrant - meaning that they can be called multiple times and their function will remain the same regardless of program state. A function that has a void return type and takes no parameters is usually an indication of a non-re-entrant function.
The use and location of printf statements depends on your program structure and what you intend your program to do. There's no right or wrong place to use them, but in some environments you may wish to locate them in one module (code file) for convenience e.g. the output is formatted or directed in a particular way.

C adds a reference to array, not a value

I am new to C and have never done anything with a non-OOP language.
I have an array of structs. It is global to the class and I parse a json with the results ending up in above mentioned array. I create an object (?) based on the struct that offers one property for every entry. After adding the items, the array turned out to have the same value on all of the positions.
I did remember C being tricky when it comes to values and pointers/references so I have made a little test to see whether the array actually only took the reference:
typedef struct {
char* name;
} ww_item ;
char nameW[40];
// iterating through json {
// strcpy(nameW, data);
ww_item w = { nameW };
ww_items [ position ] = w;
strcpy(nameW, "d"); //replaces the "Hello" with "d" in all previous ww_items
Obviously it does, which explains why my array ends up being a repetition of the last element that has been added to it instead of listing all the different strings I have added to it.
I am unable to find any short information on this and unfortunately my deadline is too close to read through a whole C book now. I'm pretty sure that my assumptions so far are true but now I do not know what to search for/ to look for in order to solve this problem.
I'm okay with an ugly solution or workaround but at the moment I am just stuck with this.
Thank you for your help.
Change the name member from a pointer to an array.
typedef struct {
char name[40];
} ww_item ;
and then use strcpy()
strcpy(ww_items[position].name, w);
There's no need for the w variable.

Best way to store constant data in C

Let's say I'm making a C program which display information about a precious stone when the user enter the stone's name.
The stones names never change and there are less than 20 of them so reading them from a external file at runtime seems a bit overkill.
I also need to access those names from multiple files (let's say two).
What I usually do is I declare a global char * array like so:
char *g_rsc_names[] = {"linemate", "deraumere", "sibur", "mendiane", "phiras", "thystane"};
in the file I need to use those. This look pretty fine to me but this only allow me to access the names in the file where I declare this global array.
In that case, what is the best/cleanest way to store the stones names?
You can wrap your array with a function which returns the const char* to the appropriate stone name and put that declaration into your global header file you include in multiple files:
const char* get_stone_name(size_t id);
Inside a source file define the get_stone_name like:
const char* get_stone_name(size_t id) {
static const char* const names[] = {
"linemate", "deraumere", "sibur", "mendiane", "phiras", "thystane"
};
return (id < (sizeof(names) / sizeof(names[0])) ? names[id] : "");
}
Decaring names as static will guarantee that won't be initialized more than once, and as a side option you can prevent the user to index your array out of bounds.
Define an enum with symbolic names for each stone. You would then store the enum value in the file instead of the name.
You could then define a function which will return the associated string for the given enum.
enum stones {
STONE_LINEMATE,
STONE_DERAMERE,
...
};
const char *stone_name(int stone)
{
switch (stone) {
case STONE_LINEMATE:
return "linemate";
case STONE_DERAMERE:
return "deraumere";
...
default:
return "";
}
Put a public declaration of the stones' data type in a header file, say stones.h:
// This lets any file that includes stones.h know that you've defined
// a variable named g_rsc_names.
extern char const *const g_rsc_names[];
The variable is defined as an array containing some number of character (string) pointers that will never change that each point to characters (strings) that will never change. This is to prevent programmer errors later and gives some hints to your compiler for optimization.
Then, in another file, stones.c:
// Populate the array.
char const *const g_rsc_names[] = {
"linemate", "deraumere", "sibur", "mendiane", "phiras", "thystane"
};
Now, include stones.h wherever you want to reference the array. Make sure to compile the stones.c file and link it to your binary.

parsing a .conf file in c

Perhaps this bridge likely has been crossed many times and in many ways... reading a simple text .conf file and acting upon its entries.
In my case, the file format is simple.. a series of tokens and assignments, as in:
token_name_1 value
with a tab character as the field delimiter and a unix line-ending for each the record.
The .conf file directly alters certain program configurations, all of them stored in a single structure. Variables of types Integer, float, char[], and *char are represented in the structure.
A quick but boring approach involves, for example:
if (strcasecmp(token,"token_name_1")==0)
token_name_1=value;
But I determined that it would be sweet to do the deed in a nice tight loop. In C.
So it seemed best to construct an array which provides pointers to each of the structure variables I wish to expose; another that provides the name of the variable; and a third which describes the stored data type and a desired default value.
These look like this:
const char* allowed_tokens[] =
{
"loglevel",
"debugecho",
"errorSqlDisable",
"ClearErrorDbOnExit",
"\0" // terminates list
}
int *varpointers[] =
{
&appinfo.nLogLevel,
&appinfo.debugEcho,
&appinfo.OWFSLogLevel,
&appinfo.OWFSLogEchoToDisplay,
0 // terminates list
};
char *varDatatypes_defaults[] =
{
"I|6", // for LOG_INFO
"B|false",
"I|0",
"B|true",
"\0" // terminates list
};
The loop looks like this (pseudocode):
row=0;
while (read a line of the .conf file into cLine)
{
get the token_name and value from cLine
check if allowed_tokens[row]==0 and if true, exit the loop
// example cLine= "debugecho false"
find match to "debugecho" in allowed_tokens. This provides an offset into varpointers and varDatatypes.
get the default data type and default value tokens from varDattypes_defaults[row]
Do the assignment. For example, if the data type=="I":
*varpointers[row]=atoi(value);
++row;
}
This technique works fine, but there are two problems.
It would be preferable to combine the three arrays into a single array. Is there a best practice here?
The array of pointers (varpointers[]) is defined as *int. I did so as I want it to hold pointers. However if the variable pointed to is not an integer data type, warning: initialization from incompatible pointer type is triggered. Of course, char * and int * cannot be mixed... so how otherwise could this be done such that a single pointer array is used?
I realize I can do all this in c++. This luxury is not an option at this point.
You can combine them into one array by structs, e.g.
typedef struct { char *token; void *var; char *defaults; } the_type;
the_type the_data[] = { { "loglevel", (void*)&appinfo.nLogLevel, "I|6" },
{ "debugecho", (void*)&appinfo.debugEcho, "B|false" },
...
};
The generic pointer type is void *. Your code has to ensure you use the correct type when actually writing to the variable being pointed to, e.g. *(int*)the_data[0] = 42;.
I would use an enumeration to specify the types so you don't have to parse a string. The values could be stored in an union.
typedef enum {
BOOLEAN,
INTEGER,
} type_t;
typedef union value {
bool boolean;
int integer;
} value_t;
typedef struct token {
char *name;
type_t type;
value_t value;
} token_t;
Now you can define your defaults like so:
token_t data[] = {
{ "loglevel", INTEGER, { 6 } },
{ "debugecho", BOOLEAN, { false } },
{ "errorSqlDisable", INTEGER, { 0 } },
{ "ClearErrorDbOnExit", BOOLEAN, { true } },
{ 0 }
};
This will get pretty cumbersome if the number of configuration keys gets large. You might want to think about storing the configuration in a hash table or a tree.
Here is a short example that seems to accomplish what you want.
If we are talking about the same data type, use double pointers (you get an array of arrays)
Declare a struct holding your pointers, then use a pointer to your struct to work on.
For declaring a general pointer, you can use void instead of int. But then every time you have to cast the pointer to use it properly.

Resources