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.
Related
I made a simple dictionary code, and surfed for an hour, and I found a file I/O code. But my compiler(I use Microsoft visual C++) says my code(unfortunately, the core part of the code) is wrong. but I can't get it. What is actually wrong and why???
/*
DosDic ver 1.0.0 2015-07-03
*/
#include<stdio.h>
#include<string.h>
char key = 0;
FILE *fp; //set a file pointer var
fp = fopen("dicdata.dat","r"); //open a file
int b = 0;
int trial = 0;
char result[];
char searchfor[] = fp; //save a whole list of dictionary in a var
int i;
char sb[]; //var for search in a list
int getsearchtrial(char sb[]){
for(i=0;i=strlen(sb);i++){ //how much I tried to reach to the word
switch((int)searchfor[b]-(int)sb[i]){ //are two alphabets same?
case 0 :
default : i=0;
}
b++; //keep finding in a list
trial++; //try again
}
return trial;
}
int adress;
int mainpage(){
printf("Type what you want to search : ");
scanf("%c",sb[ ]);
getsearchtrial(sb[ ]) - strlen(sb[ ]) = adress; //where the word is located in the list
for(i = adress;i = adress + 30; i++){ //print
printf("%c",searchfor[i]);
}
printf("Thank you for using DosDic ver.1.0!"); //thank you!
}
void main(){ //call all those functions
mainpage();
fclose(fp); //close list
}
//and whats wrong with this? i cant even get it, but it's not working
Multiple issues.
First of all, you can't assign the result of fopen to fp outside the body of a function; you must move fp = fopen("dicdata.dat", "r"); to within the body of one of your functions (getsearchtrial most likely).
Secondly, you don't read from a file by simply assigning a file pointer to an object; you must use a library function like fscanf or fread or fgets. Assuming your file contains a single string of length 80, you'd need to write something like
char searchfor[81] = {0}; // make sure string is initially empty,
// extra space for string terminator
if ( !fgets( searchfor, sizeof searchfor, fp) )
{
// error reading from file
}
Of course, this depends on how your input file is structured. If it contains a list of strings, then you'll need to use a multidimensional array (or some other structure).
Third, when you declare an array, must specify its size before you can use it. result and searchfor are incomplete array definitions.
Finally, this line
getsearchtrial(sb[ ]) - strlen(sb[ ]) = adress;
needs to be reversed; the target of an assignment must be on the left of the assignment operator.
You need to step back and learn how to write C code from the ground up.
There is so much wrong I'm not even going to itemise it all here - most of it seems to stem from your lack of understanding of arrays in C.
Most notably...
You can't declare an array and not initialise it or specify a size.
You can't assign a FILE * to a char array (and expect decent
results).
You can't execute a statement like fp = fopen at the
global scope like you are.
Try this tutorial and you may fix 95% of your problems, then go from there.
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.
Alright. So I have this program in C where I take a string with arguments and values (Such as: "GO 45 STOP 15"). The goal is to parse the string and place the argument with its corresponding value into a typedef structure to work with later on.
This is what my structure looks like:
typedef struct {
char* keyword;
double value;
} parameter;
Here are some copies of my code that I am having issues with.
Both main() and initParams() are in the same file and therefore both have access to the same #defines...
main():
#include <stdio.h>
#include <stdlib.h>
#include "findArgs.h"
#define STR0_SIZE 80
#define LIST_SIZE 4
#define MAX_PARAMS 15
void main(){
int i;
char str0[STR0_SIZE] = "LEFT 45 GO 686 GO 34.3 STOP 56 RIGHT 26"; //Input String
char* wordList[LIST_SIZE]={"GO", "STOP", "LEFT", "RIGHT"};
int num_arg = 0; //Number of arguements in str0 (each space denotes the end of an arg)
parameter* param;
initParams(param);
replaceSpaces(str0, &num_arg);
findWords(param, str0, num_arg);
}
initParams:
void initParams(parameter* param){
int ctr0, ctr1;
param = (parameter*) malloc(MAX_PARAMS * sizeof(parameter));
printf("\n%i\n", sizeof(parameter));
for(ctr0=0;ctr0<MAX_PARAMS;ctr0++){
param[ctr0].keyword = "";
param[ctr0].value = 0;
}
}
ok some quick explainations. initParams is for allocating the memory for each of my parameters. I am assuming that I will not have any idea how many parameters will be included in the string and plan on determining the number in the string later in the program. I do know that I will not accept more than parameters in the string.
After allocating the memory, I loop through each one and initialize each value to either an empty string or 0. (I do realize this is probably unnecessary, however I have done this as part of my code troubleshooting.
Continuing on, replaceSpaces() simply loops through the string and replaces each occurrence of ' ' with a '\0'. It also counts the number of arguements present in the string so that I know how many new strings I have just created by adding null terminators.
Now the tricky part in which I am having difficulty.
#define MAX_ARG_LENGTH 20
void findWords(parameter* param, char* str0, int num_arg){
parameter temp[countWords(str0, num_arg)];
int i;
int ctr0,ctr1, ctr2=0;
int word=0; //flag
char tempStr[MAX_ARG_LENGTH]="";
char* c0 = str0;
for(ctr0=0; ctr0<num_arg; ctr0++){
word=0;
ctr1=0;
if(((*c0 > 'a') && (*c0 <'z')) || ((*c0 > 'A') && (*c0 <'Z'))){
word=1;
tempStr[ctr1]=*c0;
ctr1++;
}
while(*c0 != '\0'){
c0++;
if(word)
tempStr[ctr1++] = *c0;
printf("\ntempStr: '%s'\n", tempStr);
}
if(word){
param[ctr2].keyword = tempStr;
printf("%s\n", param[ctr2].keyword);
ctr2++;
}
c0++;
}
for(i=0; i<num_arg/2;i++){
printf("'%s'\n", param[i].keyword);
printf("'%g'\n", param[i].value);
}
}
This function works properly at finding each word in the string and storing it in tempStr. My issue is with assigning it to my parameter array back in my main(). I have tried assigning them to a temp array of parameters and then setting "param" equal to the temp array. However due to the fact that param is a pointer, when I assign it a local location, after the function is finished, the memory is freed and lost. Enter my idea to use malloc to predefine memory for them and assign it after.
This is my current output when I compile and run the code. I added comments to clarify
16 //sizeof(parameter)
5 //Number of words in str0
LEFT
GO
GO
STOP
RIGHT
'RIGHT' //Things in single quotes are prints from the array of parameters
'8.05316e-315'
'RIGHT'
'0'
'RIGHT'
'8.04051e-315'
'RIGHT'
'0'
'RIGHT'
'0'
MAIN: //I printed these in main using the same for loop seen in findWord()
'▒▒'
'8.05316e-315'
'▒▒'
'0'
'▒▒'
'8.04051e-315'
'▒▒'
'0'
'▒▒'
'0'
If anyone can help me properly assign the contents of tempStr to a parameter in my array declared in main I would be greatly appreciative. Please Let me know if you need any more information.
THANK YOU ALL!! I GOT IT!!!
Rather than make "tempStr" I just assgned the characters directly to the param[index].keyword. It worked like a charm
Thank you guys very much! I had read many different Qs and As here before but this was my first time posting. I am very excited with how quickly you guys were able to reply.
Thanks again!
~Nick
I think you are misunderstanding what param[ctr2].keyword = tempStr; does It does not copy the string in tempstr to keyword it just makes keyword point to tempstr, which means all the keywords will point to the tempStr variable and will be invalid if you access it outside this function.
What you want to do is to make
char* keyword;
into
char keyword[MAX_ARG_LENGTH];
And use something like strcpy or strncpy to do the copying.
You also do not appear to be setting value anywhere
I'm trying to split a char* to an array of char* in C.
I'm used to program in Java / PHP OO. I know several easy way to do that in these languages but in C... I'm totally lost. I often have segfault for hours x)
I'm using TinyXML and getting info from XML File.
Here's the struct where we find the array.
const int MAX_GATES = 64;
typedef struct {
char *name;
char *firstname;
char *date;
char *id;
char *gates[MAX_GATES];
} UserInfos;
And here's where I fill this struct :
UserInfos * infos = (UserInfos*)malloc(1024);
infos->firstname = (char*)malloc(256);
infos->name = (char*)malloc(128);
infos->id = (char*)malloc(128);
infos->date = (char*)malloc(128);
sprintf(infos->firstname, "%s", card->FirstChild("firstname")->FirstChild()->Value());
sprintf(infos->name, "%s", card->FirstChild("name")->FirstChild()->Value());
sprintf(infos->date, "%s", card->FirstChild("date")->FirstChild()->Value());
sprintf(infos->id, "%s", card->FirstChild("filename")->FirstChild()->Value());
////////////////////////
// Gates
char * gates = (char*) card->FirstChild("gates")->FirstChild()->Value();
//////////////////////////
The only problem is on 'gates'.
The input form XML looks like "gate1/gate2/gate3" or just blank sometimes.
I want gate1 to be in infos->gates[0] ; etc.
I want to be able to list the gates array afterwards..
I always have a segfault when I try.
Btw, I don't really now how to initialize this array of pointers. I always initialize all gates[i] to NULL but It seems that I've a segfault when I do
for(int i=0;i
Thanks for all.
It's OK when I've only pointers but when String(char*) / Arrays / Pointers are mixed.. I can't manage =P
I saw too that we can use something like
int *myArray = calloc(NbOfRows, NbOfRows*sizeof(int));
Why should we declare an array like that.. ? x)
Thanks!
The problem that people frequently have with XML is that they assume all the elements are available. That's not always safe. Thus this statement:
sprintf(infos->firstname, "%s", card->FirstChild("firstname")->FirstChild()->Value());
Isn't safe to do because you don't actually know if all of those
functions actually return valid objects. You really need something
like the following (which is not optimized for speed, as I don't
know the tinyXML structure name being returned at each point and thus
am not storing the results once and am rather calling each function
multiple times:
if (card->FirstChild("firstname") &&
card->FirstChild("firstname")->FirstChild()) {
sprintf(infos->firstname, "%s", card->FirstChild("firstname")->FirstChild()->Value());
}
And then, to protect against buffer overflows from the data you should
really be doing:
if (card->FirstChild("firstname") &&
card->FirstChild("firstname")->FirstChild()) {
infos->firstname[sizeof(infos->firstname)-1] = '\0';
snprintf(infos->firstname, sizeof(infos->firstname)-1, "%s", card->FirstChild("firstname")->FirstChild()->Value());
}
Don't you just love error handling?
As to your other question:
I saw too that we can use something like int *myArray =
calloc(NbOfRows, NbOfRows*sizeof(int)); Why should we declare an array
like that.. ? x)
calloc first initializes the resulting memory to 0, unlike malloc.
If you see above where I set the end of the buffer to '\0' (which is
actually 0), that's because malloc returns a buffer with potentially
random (non-zero) data in it. calloc will first set the entire buffer
to all 0s first, which can be generally safer.
I have a struct like this:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
Can I write something so that when I do this:
string s;
the length property is zero, instead of whatever happens to be in the memory? data works well, as it's preset to zero or a null pointer.
Example of what happens right now:
string s;
printf("length: %lu\n", s.length);
printf("pointer: %lu\n", (unsigned long) s.data);
Result:
length: 140737488347584
pointer: 0
I want to avoid having to call an initialisation function on each new string just to set length to zero.
More information
Now that I think about it, it may not be really necessary to do this in my particular case (though it would be nice) because most people would initially set the string through ctou (which imports UTF-8 from char pointer) and that function sets length to zero anyway.
You could use
string s = {0,NULL};
To combine the two previous answers (sort of) I'd define something like
#define STRING_INITIALIZER {0, NULL}
.
.
string s = STRING_INITIALIZER;
BTW, your struct declaration itself looks weird for a string. Either this is not a string as we usually understand it in C but merely a dynamic array of unsigned, or it is really a string and then this should be char*.
The accepted answer answered the question that you asked, but didn't address whether you ought.
Your string is a class and has class semantics. The initializer may be fine for kernel code where every last instruction counts, but in application code your static initializers are ugly and error prone.
It is possible to write classes in C, the stdio FILE type is a fabulous example, and here is the same idea applied to your string class:
typedef struct {
int length;
char *data;
} String;
String *sopen() {
String *s = malloc(sizeof(String));
if(s) {
s->length = 0;
s->data = NULL;
}
return s;
}
int sclose(String *s) {
free(s->data);
free(s);
return 0;
}
int main()
{
String *s = sopen();
return sclose(s);
}
Where I've followed the FILE* function name style for metaphoric reasons. Yep, there's more code. Yep, you have to explicitly deallocate the structure; but note that even though you were counting on auto class initialization in your code sample, if data was ever allocated, you couldn't count on leaving scope to automatically deallocate the storage for you.
This approach also has the merit of abstracting the type of data from the users of the class. As there seems to be some confusion about what type you really want to use, this flexibility may come in handy.
#define DEFINE_STRING(s) string s = {0, NULL}
{
DEFINE_STRING(s);
}
You can use a macro to "do this automatically"