How to change a variable whose name is the user input? - c

For example, I have this block:
int nFirst, nSecond;
char sInput[10];
printf("Which variable to change to 10?");
scanf("%s", &sInput);
// BAD - inflexible and unmaintainable
if(strcmp(sInput,"nFirst") ==0){
nFirst = 10;
}
else if (strcmp(sInput,"nSecond")==0) {
nSecond =10;
}
Is there a nice way to do this? like treat a string as if its a variable name?

No, there is no "nice" way of doing this in C. Variable names (typically) aren't preserved in the generated machine code, except to support debugging. C doesn't have a built-in mechanism for translating a string value into a reference to a variable of the same name.
You would have to map variable names to variables manually. You could build a lookup table, associating a string value with the address of the corresponding variable:
struct vn {
char *varname;
void *addr;
Typeinfo t;
};
where Typeinfo is some enumeration or other mechanism for encoding the type of the variable, giving you something to the effect of
int foo;
double bar;
char *blurga;
struct vn varsByName[] = { {"foo", &foo, IntType},
{"bar", &bar, DoubleType},
{"blurga", blurga, CharPtrType} };
I don't recommend doing this.

Another, platform-dependent approach is to put all your variables into a shared library and then have access to them by names. Have a look at dlsym/dlopen functions.
void* handle = dlopen("mysymbols.so", RTLD_LOCAL | RTLD_LAZY);
int* var = (int*) dlsym(handle, user_typed_name);
*var = 10; /* modify the variable */

You could implement something like a dictionary or a two-dimensional array which contains the "variable name" and the value. Then this comes down to setting an array element to a new value.
Other than that: C# and other object oriented languages would allow this through reflection, but as C itself isn't object oriented, you can not do that (C++ support for this seems to be very limited).

You can do it with a macro:
#define MAYBESET(name) if (strcmp(sInput, #name) ==0 ){ name = 10; }
#name is the real value of name changed to a string literal.

For a small number of variables then your algorithm should perform well. If there are many variables that could be changed, rather than just two, then another algorithm should be considered. Making this pretty and clear isn't exactly easy in C.
If you really wanted this to be faster you could either do a hash table or use a switch/case like:
int First, Second; // Note that I got rid of your leading n
char sInput[10];
printf("Which variable to change to 10?");
scanf("%s", &sInput);
// BAD - inflexible and unmaintainable
// referring to character array overflow potential, I assume
switch (sInput[0])
{
case 'F':
if (0 == strcmp("irst", sInput+1) )
{
First = 10;
} else
{
// error
}
break;
case 'S':
if (0 == strcmp("econd", sInput+1) )
{
Second = 10;
} else
{
// error
}
break;
default:
// error
break;
}
If you don't like the way that this looks then you could use macros (#define) to make it less big looking, but it would turn out the same. Another option that you could employ would be to write a small program that output the source code of this program which would handle all of the repetitive and tedious parts.
Another way to do this, if all of the variables are of the same type, would be to create an array of them and input their index in rather than a name, but then you have to add code to check against inputting an index out of range of the size of the array.

Related

I don't understand how pointers work in this code?

I don't understand this part of the code below. I mean alloc_MY_CAR() returns some array and how does & work so that newTab->pFunFree = &free_MY_CAR sees this array which newTab->pDat returns?
I don't understand pointers well. I only know that & store address of variable and * is a pointer or a value of the variable.
Could anyone guide me on how to use it properly and how does it work? I'm a beginner, so don't be so hard on me.
Thanks in advance!
#pragma once
struct MY_CAR {
char *model;
int year;
};
void print_MY_CAR(void* pdata);
void free_MY_CAR(void *pdata);
MY_CAR* alloc_MY_CAR();
switch (typ) {
case 0:
newTab->pDat = alloc_MY_CAR();
newTab->pFunFree = &free_MY_CAR;
newTab->pFunPrint = &print_MY_CAR;
break;
}
MY_CAR* alloc_MY_CAR() {
MY_CAR* tab = (MY_CAR*)calloc(1, sizeof(MY_CAR));
if (!tab) {
exit(0);
}
else {
char model[125];
printf("Podaj model: ");
scanf("%s", model);
tab->model = (char*)calloc(strlen(model) + 1, sizeof(char));
strcpy(tab->model, model);
printf("Podaj rok: ");
scanf_s("%d", &tab->year);
}
return tab;
}
void free_MY_CAR(void *pdata) {
MY_CAR* car = (MY_CAR*)pdata;
if (!car || !car->model) return ;
free(car->model);
free(car);
}
Notice that the function free_MY_CAR has an argument of type void*,
a pointer to a "void" type
(which is a C idiom for a pointer to something without telling the type of the thing pointed to),
and the first thing it does is to reinterpret that pointer as a pointer to a MY_CAR.
So the function is probably intended to be called like this:
newTab->pFunFree(newTab->pDat);
That is, the way the functions "know" what pointer was returned by
alloc_MY_CAR() and stored in newTab->pDat
is that the programmer explicitly tells the functions what pointer
is stored in newTab->pDat.
The advantage of doing such things is that it allows some code to do some operation on a data structure without necessarily having to know what kind of data structure it will actually operate on when the program actually runs.
In the call to pFunFree above, newTab could have been initialized by the case 0 code shown in the question, but there could be another case
that initializes it with alloc_MY_JOB(), &free_MY_JOB, and &print_MY_JOB,
where the MY_JOB functions allocate/free/print a data structure that is quite different from the data structure used by
alloc_MY_CAR(), &free_MY_CAR, and &print_MY_CAR.
Then if you call
newTab->pFunPrint(newTab->pDat);
we might not be able to predict when we write the code whether it will print the contents of a data structure created by
alloc_MY_CAR() or by alloc_MY_JOB();
but we can predict that it will print the detailed information it has
about your car, or your job, or whatever was read from the data file and stored in newTab.
The property that we can make a function call that uses a data structure in a way appropriate to that data structure, without having to know when we write the code what the type of data structure will be, is called
polymorphism.
This is a cumbersome idiom and there are lots of ways to get it wrong.
One of the selling points of C++ is to enable people to write polymorphic objects more easily than this.

C - Convert string to variable name

How can I convert a string into a variable name? E.g. I have a list of strings:
"str1", "str2", "str3", etc.
And a structure:
struct my_struct {
int str1;
int str2;
int str3;
} m = {5, 10, 15, ... etc};
Given a string "str2", I want to print the variable associated with that
name m.str2. Does C have any way to do this?
Thank you!
This is simply not possible in C.
Check out this question for more details.
How to return a variable name and assign the value of the variable returned in c
To quote Wichert, 'I suggest that you reconsider the problem you are trying to solve and check if there might not be a better method to approach it. Perhaps using an array, map or hash table might be an alternative approach that works for you.'
In C you cannot create variable or symbol names dynamically.
Here's one way.
if ( strcmp(str, "str2") == 0 )
{
// Use m.str2
}
That will be a problem with hundreds of variables. You'll have to come up with some other mechanism in that case.
I will suggest a slightly simpler, albeit maybe not as efficient solution.
This was a solution I came up with for a project after consulting with one of my professors.
Essentially, strings are just ASCII characters, and C file containing variable names can be thought of in the same way.
Thus, suppose you have a list of strings that you would like to turn into variable names for integers.
First, define your structure in a header file that can be accessed by all files in your directory, for instance 'struct.h'.
The first step is to convert the string names to their respective integers
Simply create an empty header, called variable_names.h, include struct.h, and once and for all invoke the following loop in your main file:
const char *strings[] = {"str1", "str2", ... }
fp = fopen("variable_names.h", "a");
fprintf(fp, "#ifndef FILE1_H \n");
fprintf(fp, "#define FILE1_H \n");
fprintf(fp, "extern int* m_integers = {");
int i;
for(i = 0; i < sizeof(strings) - 1; i++){ fprintf(fp, "m.%s,", strings[i]);}
fprintf(fp, "m.%s } ", strings[i+1])
fprintf(fp, "#endif");
Now you have a linear mapping between the string name and value in your structure via the m_integers array. Next is to create some mapping that takes in the string name and points it to this integer. I will use UTHASH, but there are certainly other ways.
Thus, in your main file,
#include "uthash.h"
#include "variable_names.h"
...
struct opcode_table{
char* opcode_key;
int opcodes_val;
UT_hash_handle hh;
};
struct opcode_table *mapping = NULL;
struct opcode_table* s = NULL;
for (int i = 0; i < opcode_size; i++){
s = (struct opcode_table*) malloc(sizeof(*s));
s->opcodes_key = strings[i]; // the string
s->opcode_val = m_integers[i]; // the integer
HASH_ADD(hh,mapping, opcodes_key, sizeof(int),s);
}
^ Please go easy on the code, just a rough example of what could be done. I'm sure there are some mistakes, but high level I believe this should work.
As on overview, the idea is essentially, you wrote to an external file the ascii characters "m.string1", which once is written, is interpreted as an integer via the structure definition, yielding you your desired outcome. Now, you must simply look up the string in the hash table, and you get the integer in the structure.
Also, I would appreciate any feedback if someone finds a better way or this approach is flawed. Thanks!
Here is one way, please check the sample code I have written. I have used integer pointer ptr to do this.
#include <stdio.h>
#include <string.h>
const char *s[] = {"str1", "str2", "str3", "str4", "str5", "str6", "str7", "str8", "str9", "str10"};
struct temp
{
int str1;
int str2;
int str3;
int str4;
int str5;
int str6;
int str7;
int str8;
int str9;
int str10;
}m = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
main()
{
char str[10];
int *ptr;
int i;
ptr = &m.str1;
printf("enter string: \t");
scanf("%s", str);
for(i=0;i<10;i++)
{
if(strcmp(str,s[i]) == 0)
{
break;
}
}
printf("value = %d\n", *(ptr+i));
}
Please correct me if any mistakes.
What you are wanting is what the Smalltalk Language had used in it's Interpreter in the 1980;s and what Python still uses to create Object Variables from string char's through a TTY Command Shell Program in C language.
We do these by using structs with a nested struct next. But the actual variable, names are never actually declared. They are however matched by a conditional search for their stored char name in a struct or if it does not exist it creates them.
If it does exist in the struct list it will conditionally find() it and its stored value or assign its value depending on what your program has it designed to do.
An example of this is understood best by the Token's being used for (tok),(s),(t),(e) and several others as look-aheads read in by a token stream:
if (tok == "IDENT";) {
When it finds a identifier(variable tag from lex) token as above it will look ahead and fetch the variable name, then either create it, perform a calculation of its look-ahead contains another variable after another char type definition such as "CHAR" or "FLOAT"(for a double)etc.
What it does now is to set everything conditionally as it's being read into the struct list assigned by the tok token stream.
"CHAR" "x" "EQUALS" "INT" "5" "NEWL(for \N)" "CHAR" "y" "EQUALS" "INT" "5" "NEWL" "PRNT" "CHAR" "x" "NEWL".
So basically all variables through void functions are conditionally being assigned to a struct list and likewise having their values stored by them.
And it is not the variable you need to match its stored variable name. Its only the match it requires from a single tok variable and it's look-aheads that you need--
struct Var v; //--declared in .h then--
if(tok == 'CHAR') //--and--
v = {tok2, s, t} //
"tok2" being your vars char name and "s" and "t" being look-aheads to fetch, calculate and or assign them. Basically Python uses one C variable named tok to name them all. Then matches make them both dynamic and easy for Python to use them. atoi and strtod make integer and doublke conversion on the fly also. Its advanced stuff.
This whole process is called "Scanners" and "Calculators" in early ANCI C. Study Dennis Ritchie and Tobias Shrighner. Tobias worked on several Interpreters in fact.

Counting of objects in linked list

I have a linked list and I need to count only some of records according some criteria. I have got this code.
int count_records() {
int number = 0;
RECORD *re;
char criteria[20];
for (re = first; re != NULL; re = re->next) {
criteria = (re->criteria);
if(criteria=="something")
number++;
}
return number; }
Structure of linked list is this:
typedef struct record {
char criteria[20];
struct record *next;
} RECORD;
Problem is that it gives me this error on line criteria = (re->criteria); Error: Invalid array assignment
Any ideas?
Thanks.
You have arrays of char´s. To copy or compare an array, you´ll need to copy/compare each element separately instead of using = and == on the whole array in one go.
And instead of making a loop, you can use strcpy and strcmp in this case:
strcpy(criteria, re->criteria);
if(!strcmp(criteria, "something"))
By the way, this is more C than C++. If you want a C++-like solution, see std::string (then you can work with = and == too)
Indeed, you can't copy arrays using =. Neither can you compare them using ==. They are quite strange, unfriendly things, which need a certain amount of care to use.
If you want to use arrays, you can use the C library to compare them:
if (std::strcmp(re->criteria, "something") == 0)
Since this is C++, you might prefer to use std::string to represent strings; then it's just
if (re->criteria == "something")
and you can copy it with = if you need to (although you don't need to here).
In C++ you can and should use std::string for handling strings. You can find the reference (here).
Just define criteria as std::string criteria; instead of char criteria[20];.
Don't forget to add #include <string> to the include section.
You need to use memcpy in order to copy arrays, but be careful using memcpy when exposed on a public interface. I think there was a recent security issue involving this...
I think that you may wish to pass in the criterion to your count_records() function. I'd render it like this:
int count_records(RECORD *first, const char *criterion) {
int count = 0;
RECORD *re;
for (re = first; re != NULL; re = re->next) {
/* add to count if the strings match */
if(!strcmp(criterion, re->criteria))
count++;
}
return count;
}
Note that it also doesn't rely on first being a global variable which makes the code more reliable and easier to understand.
If you want to copy a char array into another, you need to use strcpy. For example:
// will copy from array1 to array2
strcpy(array2, array1);
You can't directly do array1 = array2. Because in this case you would manipulate the adresses (char *) of the arrays and not their values.
In addition, in order to compare a char array to another, use strcmp instead:
if(strcmp(criteria, "something") == 0)
P.S.: Since you're using C++, std::string is your friend, which you can do assignment using = and comparison using ==.
Dealing with strings in C is a royal pain when you are starting out with the language. You can checkout an online tutorial to get you started.
In the mean time, you can change your code to:
for (re = first; re != NULL; re = re->next) {
if (strcmp(re->criteria, "something) == 0)
number++;
}
You don't need to copy re->criteria to a local variable.

Long arguments list, how to process them nicely, now I have many if/else statements ... pure C

I have an application where the arguments list cant be reeeealy long. I can run my app like this:
./app -operations a b c d e f g h i j ...
And so on. My a,b,c ... are algorithms which I would like to run (functions defined in my code). To be able to execute them, I have something like this:
if(a)
funA();
if(b)
funB();
if(c)
funC();
...
It does not look nice, does it? I must say, there's much more calls than just 26, since my application grows and grows, my arguments list grows too. I'm looking for a fancy way to make it simpler/prettier. Is it possible, anyone with an idea?
I dont want to use C++ nor external libraries for making it simpler. Can it be done in pure C?
Here is a very simplified possible option:
#include <stdio.h>
// create a common structure to hold all your
// function parameters;
typedef struct Parameters
{
int p1;
int p2;
} Param_Type;
// sample function 1
void func1( Param_Type *params ) {
printf("hi from func1: %d\n", params->p1 );
}
// sample function 2
void func2( Param_Type *params ) {
printf("hi from func2: %d\n", params->p2 );
}
int main() {
Parameters p;
// parse the command line and populate the parameters struct;
p.p1 = 1;
p.p2 = 1;
//create a lookup table with pointers to each function.
void (*F_A[2])(Param_Type *) = {func1, func2};
//You will still need some function, that given a set of arguments, can
// derive and return an index into the array that maps to the correct
/ function.
int func_idx = your_mapping_function(...) // todo
// dispatch the correct function call.
(*F_A[func_idx])(&p);
return 0;
}
You can use use getopt() to read the command line parameters.
And I don't see any optimization in the way you are deciding what action to take depending upon the arguments. I'd say it's just a bad design of doing things. You could try changing your approach.
You could use enums and function pointers to define handlers for every different set of arguments.
Something in the lines of:
typedef enum {
ARG_A,
ARG_B,
ARG_C,
// etcetera
MAX_ARGS
} CmdArgId;
bool cmdArgStates[MAX_ARGS];
typedef void (*CmdHandler_f)();
CmdHandler_f cmdHandlers[MAX_ARGS] = {
// TODO: set function pointers
};
int main()
{
// set cmdArgStates[] indexes to true or false,
// according to the program command line.
ParserCmdArgs();
for (int i = 0; i < MAX_ARGS; ++i)
{
if (cmdArgStates[i] == true)
{
cmdHandlers[i]();
}
}
}
If you need the handler functions to have different numbers of arguments, you can define a common function with a fixed number of args and just ignore them when they are not needed. I.e.: typedef void (*CmdHandler_f)(); could also de something like typedef void (*CmdHandler_f)(int, int, int);
One idea would be to create a structure that can be used to abstract each command line option. Here is a possible method you could use to implement that idea :
Create a structure that can represent each function you need to
support, and have it hold a pointer to the function and a string for the search key.
Create an array of this structure and initialize the members accordingly
Use an algorithm, such as a binary search, to find the key in the structure array when looping through the command line arguments.
Once you have the structure from the key, you can then call the function which will handle the behavior desired in the option.
It's possible this won't apply to your situation, but this really is an implementation specific problem. If you want a more specific solution, you should probably post more details about your functions and the implementation behind them.

Pointers to variables?

Is it possible to have pointers to data variables? I know I can have, say, pointers to strings e.g. char *str[n] and I can perform a 'for' loop over those pointers to retrieve the strings ... str[i] where i is the index counter.
If I have some data e.g.
char var1;
int var2;
char var3;
and I wanted to get data from stdin I might use 3 separate calls to scanf()- just an example - to populate these variables.
Can I have 'an array of pointers to data' e.g. void *data[] where data[0] = char var1, data[1] = int var2 and data[2] = char var3, so that I could then use a single call to scanf() in a 'for' loop to populate these variables? (I'm assuming the type would have to be void to cater for the different types in the array)
I don't really recommend this, but here's the implementation you describe:
char var1;
int var2;
char var3;
void *vars[3];
char *types[3];
vars[0]=&var1; types[0]="%c";
vars[1]=&var2; types[1]="%d";
vars[2]=&var3; types[2]="%c";
for (int i=0;i<3;i++)
{
scanf(types[i],vars[i]);
}
You need the array of types so that scanf knows what it should expect.
However, this procedure is extremely unsafe. By discarding any type-safety, you invite crashes from malformed input. Also, if you misconfigure types[] then you will almost certainly crash, or see unexpected results.
By the time you've set up the arrays, have you really saved any code?
There are plenty of answers here that will allow you to use either a type-safe C++ solution, or as others have recommended, calling scanf() explicitly.
You certainly could have such a void *data[] array. You wouldn't be able to read those in via scanf, though, as you need a different format specifier for the different data types.
If you wanted to do this, you could iterate over an array of
struct dataType
{
void *data;
char *format_specifier;
}
or somesuch. However, I doubt this would be a good idea - you probably want to also prompt for each value, so you'd add another char *prompt to that struct, and you'll probably need other things later as well.
I suspect the code you'd end up writing to do this would be much more effort than simply scanf-ing n times, even for quite large n.
The problem is that this void * array would be dealing with datatypes of different sizes. For this problem, you'd probably want to use a struct and maintain an array of those instead. Or you could just put your data in as a byte array, but then you'd have to know how to "chop it up" properly.
you could have an array of void*, so *array[0] = var1, etc.
To illustrate the problem..
int main(int argc, char* argv[])
{
char var1 = 'a';
int var2 = 42;
char var3 = 'b';
void* stuff[3] = {0};
stuff[0] = &var1;
stuff[1] = &var2;
stuff[2] = &var3;
// Can't really use the array of void*'s in a loop because the
// types aren't known...
assert( var1 == (char)(*(char*)stuff[0]));
assert( var2 == (int)(*(int*)stuff[1]));
assert( var3 == (char)(*(char*)stuff[2]));
return 0;
}
Not directly, no. If you're able to use C++ in this situation, the closest you could do would be to wrap each variable in an object (either something like a variant_t or some templated, polymorphic solution). For instance, I believe you can do something like this:
class BaseType
{
public:
virtual void DoScanf();
};
template<typename TYPE>
class SubType : public BaseType
{
public:
SubType(const TYPE& data) : m_data(data) {}
const TYPE& m_data;
virtual void DoScanf()
{
// Your code here
}
};
int num1;
char char1;
SubType<int> num1Wrapper(num1);
SubType<char> char1Wrapper(char1);
// You can then make a list/vector/array of BaseTypes and iterate over those.
Looks like you are trying to implement a template (C++) equivalent in C. :D exactly that is what i am trying to do, for one of my project. I think mine case is less confusing as I am using only one datatype (some project specific structure), mine array would not be intermixing the datatypes.
Hey, do one thing try using a union of various data-types you intent to use, i think reading this shall not be a problem. As when your read-function using that union reads it, will be able to read it, because of the inherit C-type safety. What i mean here is the follow the same concept which we usually use to check a endianess of a machine.
These are few idea, i am myself working on, shall be able to complete this is a day or two. And only then i can tell you, if this is exactly possible or not. Good luck, if you are Implementing this for some project. Do share your solution, may be here itself, I might also find some answer. :)
I am using the array of void pointers.
If you want an array of variables that can be "anything" and you are working in C, then I think you want something like a struct that contains a typeid and a union.
Like this, maybe: (Note, quick example, not compile tested, not a complete program)
struct anything_t {
union {
int i;
double d;
char short_str[7]; /* 7 because with this and typeid makes 8 */
char *str; /* must malloc or strdup to use this */
}; /* pretty sure anonymous union like this works, not compiled */
char type; /* char because it is small, last because of alignment */
};
char *anything_to_str(char *str, size_t len, const struct anything_t *any)
{
switch(any->type) {
case 1: snprintf(str, len, "%d", any->i); break;
case 2: snprintf(str, len, "%f", any->d); break;
case 3: snprintf(str, len, "%.7s", any->short_str); break; /* careful, not necessarily 0-terminated */
case 4: snprintf(str, len, "%s", any->str); break;
default: abort(); break;
}
return str;
}
And I forgot to add the scanf part I intended:
char *scanf_anything(struct anything_t *inputs, size_t count)
{
int input_i;
struct anything_t *i;
for(input_i=0; input_i<count; ++input_i) {
any = inputs + input_i;
switch(any->type) {
case 1: scanf(" %d ", any->i); break;
case 2: scanf(" %lf ", any->d); break;
case 3: scanf(" %.6s ", any->short_str); break;
case 4: scanf(" %a ", any->str); break; /* C99 or GNU but you'd be a fool not to use it */
default: abort(); break;
}
}
}
Formally all the solutions presented here which are using void* have the same problem. Passing a void* as a variadic argument (like scanf) which expects another type of pointer put you in the "undefined behavior" domains (for the same reason, you should cast NULL to the correct type when passed as variadic argument as well).
on most common platforms, I see no reason for a compiler to take advantage of that. So it will probably work until a compiler maker find out that there is a test in SPEC where it allows to get a 0.000001% improvement :-)
on some exotic platforms, taking advantage of that is the obvious thing to do (that rule has been put for them after all; they are mostly of historical interest only but I'd not bet anything about embedded platforms; I know, using scanf on embedded platforms can be considered as strange)
All solutions above are valid but no one has yet mentioned that you can do what you want with a single simple scanf call:
scanf(%c%d%c",var1,var2,var3);

Resources