I have the sturct token_t down below. It has two things in it.
type (enum)
value (union)
The reason why value is union, cz a token can be either a number or string.
The main problem is that I cannot design a proper function that can print this token out for me. Check out my void print_token(token_t* token) function. I know it's terrible. Just becase the printf() prints only either %d (decimal) or %s (string) I cannot print my token out. I want my function to print the token no matter what the value is.
// ===========================================================================
typedef enum token_type_t
{
ID, // Identifier
STR, // String
WHS, // Whitespace
LPR, // Left Parenthesis
RPR, // Right Parenthesis
LCB, // Left Curly Bracket
RCB, // Right Curly Bracket
LSB, // Left Square Bracket
RSB, // Left Square Bracket
EOF, // End Of File
EQL, // Equal Sign
SEM, // Semicolon
} token_type_t;
typedef union token_value_t
{
char* str_value;
int int_value;
} token_value_t;
typedef struct token_t
{
token_type_t type;
token_value_t value;
} token_t;
// ===========================================================================
// Here's the problem. I want this function to print the token no matter what type
// the value is, I want it to be dynamic. Is there any way to do that?
void print_token(token_t* token)
{
printf("Token { type: %d, value: %s }\n", token->type, token->value);
}
How do I print either string or integer in C?
Use a different printf() depending on type.
void print_token(const token_t* token) {
printf("Token { type: %d, value: ", token->type);
switch (token->type) {
case ID: printf("%d", token->value.int_value); break;
case STR: printf("\"%s\"", token->value.str_value); break;
// TBD code for other cases
}
printf(" }\n");
}
One solution is to print only a string, but convert the integer to a string conditionally:
For example:
void print_token( const token_t* token )
{
char buf[21] ;
printf( "Token { type: %d, value: %s }\n",
token->type,
token->type == ID ? itoa( token->value.int_value, buf, 10 ) :
token->value.str_value );
}
Noting that itoa() is not a standard function - you might consider that prohibitive if you have to implement your own just for this.
You have not specified which token types are integers and which are strings so if perhaps ID is not the only integer, the condition may be more complex such as:
void print_token( const token_t* token )
{
char buf[21] ;
printf( "Token { type: %d, value: %s }\n",
token->type,
token->type == ID ||
token->type == EOF ? itoa( token->value.int_value, buf, 10 ) :
token->value.str_value );
}
If you have more more integer types than string types you would do better to swap the test.
If the are just one or two of one token type and the rest are of the other, and you have a suitable integer-to-string function, the above solution is succinct, but might get cumbersome if that are more than a few of both types. In that case consider the solution below.
A switch/case using of case "fall-through" cases and a default may be easier to maintain an does not need an integer-to-string fucntion:
void print_token( const token_t* token )
{
printf( "Token { type: %d, value: ", token->type ) ;
switch (token->type)
{
// Stack all the integer token cases here
case ID :
case EOF :
printf("%d", token->value.int_value) ;
break ;
// Everything is a string
default:
printf( "\"%s\"", token->value.str_value ) ;
break;
}
printf(" }\n");
}
Again you might swap the explicit cases and default if there are more string tokens than integer.
Related
I want to make a program that reads a string with the information of a party, separates the information between "/" and then creates an object with the info.
I made a cicle, as shown in the web. If I just want to print it, it works fine, but when I try to assign it to the variables, the error happens - Segmentation Fault
My struct is the following:
typedef struct {
char description[40];
int date;
int time;
int duration;
int room;
char parent[40];
char kids[3][40]
} Party;
And the function that reads the string is:
void createParty():
Party p;
char s[LIMIT] = "John's Birthday/25032019/2230/10/1/Thomas/Anna/Jack/Sarah";
char c[2] = "c";
char *token;
int i=0;
token = strtok(str, s);
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
if (i==0)
strcpy(p.description,token);
else if (i==1)
p.date=atoi(token);
else if (i==2)
p.time=atoi(token);
else if (i==3)
p.duration=atoi(token):
else if (i==4)
p.room=atoi(token);
else if (i==5)
strcpy(p.parent,token);
else
strcpy(p.kids[j-6],token);
i++
}
I expected that all the values would be assigned with no problems, but when I try to assign the last kid, it gives me the Segmentation Fault. If I don't try to assign the last name, there is no errors.
Thanks!
the following proposed code:
eliminates the multiple testing of variable i
eliminates the use of 'magic' numbers
corrects the logic errors
corrects the syntax errors
assures that char arrays are not overflowed
cleanly compiles
needs a 'main()function to call thecreateParty()` function
properly prototypes the function: createParty()
defines the struct in a flexible manner
defines a 'tag' name so a debugger can loop at the individual fields in the struct
separates the 'typedef' from the struct definition
allows there to be more than one party, simply by changing the MAX_PARTIES to a value other than 1
documents why each header file was included
uses appropriate horizontal and vertical spacing for readability
the OPs code called strtok() at the top of the loop, so the results from the first call to strtok() were printed, but never processed into the struct
and now, the proposed code:
#include <stdio.h> // printf()
#include <string.h> // strtok(), strncpy()
#include <stdlib.h> // atoi()
#define LIMIT 500
#define MAX_PARTIES 1
#define MAX_DESC_LEN 40
#define MAX_PARENT_LEN 40
#define MAX_KIDS 3
#define MAX_KID_LEN 40
struct PARTY
{
char description[ MAX_DESC_LEN ];
int date;
int time;
int duration;
int room;
char parent[ MAX_PARENT_LEN ];
char kids[ MAX_KIDS ][ MAX_KID_LEN ]; // was missing trailing semicolon
};
typedef struct PARTY MyParty;
// prototypes
void createParty( void ); // notice 'void' parameter in prototype
void createParty() // removed extranious trailing char
{
MyParty p[ MAX_PARTIES ]; // Note: a 2 space indent level can be 'lost' with variable width fonts
char s[LIMIT] = "John's Birthday/25032019/2230/10/1/Thomas/Anna/Jack/Sarah";
char delimiters[] = "//"; // note using '//' as first slash 'escapes' the second slash
int i=0;
char * token = strtok( s, delimiters );
while( token && i < 11 )
{
printf( "%s\n", token );
switch( i )
{
case 0:
strncpy( p[i].description, token, MAX_DESC_LEN-1 );
break;
case 1:
p[i].date = atoi( token );
break;
case 2:
p[i].time = atoi( token );
break;
case 3:
p[i].date = atoi( token );
break;
case 4:
p[i].duration = atoi( token );
break;
case 6:
p[i].room = atoi( token );
break;
case 7:
strncpy( p[i].parent, token, MAX_PARENT_LEN-1 );
break;
case 8:
strncpy( p[i].kids[0], token, MAX_KID_LEN-1 );
break;
case 9:
strncpy( p[i].kids[1], token, MAX_KID_LEN-1 );
break;
case 10:
strncpy( p[i].kids[2], token, MAX_KID_LEN-1 );
break;
default:
printf( "unexpected field found: %s\n", token );
break;
}
i++; // was missing trailing semicolon
token = strtok( NULL, delimiters ); // prep for next loop iteration
} // end switch
} // end function: createParty()
I'm looking for help with printing the results of an SQL statement out in C. I'm trying not to set each variable to a pointer and then using that pointer to print the variable out. If I did, I'd have like a couple hundred variables. This is what I've tried so far. I'm literally lost on how to get this to output correctly. Any help would be appreciated.
int hstmt = DBActivateSQL(hdbc, "SELECT * FROM REG_RESULTSTABLE");
if (hstmt <= 0)
{
ShowError();
}
sprintf(uutNum, "%s \n", hstmt);
while((resCode = DBFetchNext(hstmt)) == DB_SUCCESS) {
SetCtrlVal(panelHandle, PANEL_lstregulator, uutNum);
}
Prototype of DBActivateSQL is
int DBActivateSQL (int connectionHandle, char SQLStatement[]);
It is returns int.
Hence hstmt should be declared as int type.
int hstmt = DBActivateSQL(hdbc, "SELECT * FROM REG_RESULTSTABLE");
To print it to string you need use %d not %s as hsmt is of type int.
sprintf(uutNum, "%d",hstmt);
^^------------------------//Using %d instead of %s here
The functions that you want are DBFetchNext and DBGetCol* (DBGetColChar, DBGetColDouble, ...). According to the documentation page on DBGetColChar, the flow should be something like this, where you only need one variable per column:
void print_MyTable(int hdbc)
{
char *var1;
int var2;
float var3;
int statement = DBActivateSQL(hdbc, "SELECT col1, col2, col3 FROM MyTable");
int resultCode;
while ((resultCode = DBFetchNext(statement)) == DB_SUCCESS) {
if ((resultCode = DBGetColChar(statement, 1, &var1, "")) != DB_SUCCESS) {
// Handle the error
break;
}
if ((resultCode = DBGetColInt(statement, 2, &var2)) != DB_SUCCESS) {
// Handle the error
DBFree(var1);
break;
}
if ((resultCode = DBGetColFloat(statement, 3, &var3)) != DB_SUCCESS) {
// Handle the error
DBFree(var1);
break;
}
// Print the values
printf("col1: %s, col2: %d, col3: %f\n", var1, var2, var3);
// Free the string's memory
DBFree(var1);
}
statement = DBDeactivateSQL(statement);
}
Here is the piece of code: I wonder where my mistake is?
I have a structure named country, working with linked lists, and here is my function for searching:
country *search(char *v)
{
country *c; c=head;
while(c)
{
if(strcmp(c->name,v)==0)
{return c;}
c=c->next;
if(c==head) break;}
return (void *)-1;}
In main I have (k is a int variable):
printf(" \n\tEnter name of country for searching: ");
fflush(stdin); gets(v);
k = search(v); // Function for searching
if(k>=0)
{puts("\n\t Info about Country: \n ");
When I compile this in Dev C++, I get:
[Warning] assignment makes integer from pointer without a cast [enabled by default]
How do I fix this problem?
Couple of things to fix:
The return value of search when you don't find what you are searching for:
country *search(char *v)
{
country *c; c=head;
while(c)
{
if(strcmp(c->name,v)==0)
{
return c;
}
c=c->next;
if(c==head) break;
}
// Don't use -1 as an invalid search.
// Use NULL instead.
// return (void *)-1;
return NULL;
}
Use the right variable type to assign the return value of search.
// Don't use k, which is of type int.
// Use a variable of the right type.
// k = search(v);
country* cPtr = search(v);
if( cPtr )
{
puts("\n\t Info about Country: \n ");
}
I need to compare the contents of an element of a struct to another.
struct total_owners
{
int ADT2; //id number
char arkyk[7]; //license plate number
};
typedef struct total_owners owners;
struct total_offenses
{
char arkyk2[7];
int serious; //seriousness of offense (0 or 1)
};
typedef struct total_offenses offenses;
struct total_drivers
{
int ADT;
int ADO; //license number
};
typedef struct total_drivers drivers;
what I want to compare is arkyk2 in total_offenses with arkyk in total_owners. they are both of the format XXX1234 ( three letters and 4 numbers)
this is the function I am working on
void sumpoints(offenses* b,owners* a, drivers* c, int amountowners , int amountoffenses ,int amountdrivers)
{
int totals[amountdrivers][3],i,j,h;
for (i=0;i<amountdrivers;i++)
{
totals[i][0] = c[i].ADT;
totals[i][1] = c[i].ADO;
totals[i][2] = 0;
}
for (h=0;h<amountdrivers;h++)
{
for (i=0;i<amountowners;i++)
{
for(j=0;j<amountoffenses;j++)
{
if (a[i].arkyk == b[j].arkyk2) // this is wrong (definitely)
{
if (c[h].ADT == a[i].ADT2)
{
totals[h][2] = totals[h][2]+1;
}
}
}
}
}
for (i=0;i<amountdrivers;i++)
{
printf("Total offenses per driver:\n");
printf(" ADT %d \t ADO %d \t total %d\n", totals[i][0] , totals[i][1] , totals[i][2]);
}
}
the end result should be a totals array with the id number in the first column , the license number in the second and the amount of offenses in the last.
To do string comparison, you would change
if ( a[i].arkyk == b[j].arkyk2 )
to
if( strncmp( a[i].arkyk, b[j].arkyk2, 7 ) == 0)
As was pointed out by #notlikethat, using plain strcmp may run into trouble since you have a 7 element array to store 7 characters, so there is no space for a terminating '\0'. By specifying that the comparison should stop after 7 characters, you avoid this issue.
In C: Create a function called compare that takes the two different structures as parameters and returns a bool. Inside the function just do a string comparison with strcmp or strncmp
In C++:
Go nuts with operator overloading, it might look better, and will give you the same performance.
#include<stdio.h>
int main(){
char name[20];
printf("enter a name ");
scanf("%s",name);
switch(name[20]){
case "kevin" :
printf("hello");
break;
}
printf("%s",name);
getch();
}
It seems it will not work. Is this possible? I mean is there any way we can make a switch statement of a string. How to solve the problem, actually?
Switch statements in C aren't smart like one's found in other languages (such as Java 7 or Go) you cannot switch on a string (Nor can you compare strings with ==). Switch can only operate on integral types (int, char, etc).
In your code you call switch with: switch(name[20]). That means switch(*(name + 20)). In other words switch on the 21st char in name (because name[0] is the first). As name only has 20 chars you are accessing whatever memory is after name. (which could do unpredictable things)
Also the string "kevin" is compiled to a char[N] (where N is strlen("kevin") + 1) which contains the string. When you do case "kevin". It will only work if name is in the exact same piece of memory storing the string. So even if I copied kevin into name. It still would not match as it is stored in a different piece of memory.
To do what you seem to be trying you would do this:
#include <string.h>
...
if (strcmp(name, "kevin") == 0) {
...
}
String compare (strcmp) returns different values based on the difference in the strings. Eg:
int ord = strcmp(str1, str2);
if (ord < 0)
printf("str1 is before str2 alphabetically\n");
else if (ord == 0)
printf("str1 is the same as str2\n");
else if (ord > 0)
printf("str1 is after str2 alphabetically\n");
Side note: Dont use scanf("%s", name) in that form. It creates a common security problem use fgets like this: (there is a safe way to use scanf too)
#define MAX_LEN 20
int main() {
char name[MAX_LEN];
fgets(name, MAX_LEN, stdin);
...
Switch statements work on int values (or enum), but not on char arrays.
You could do
if (strcmp(name, "kevin")==0) {
printf("hello");
}
else if (strcmp(name, "Laura")==0) {
printf("Allo");
}
else if (strcmp(name, "Mike")==0) {
printf("Good day");
}
else {
printf("Help!");
}
There are plenty of ways to go about this! For example, use a...
3-letter hash
#include <stdio.h>
int main(){
char name[20];
printf("enter a name ");
scanf("%s",name);
switch((int)*name * (int)*(name+1) * (int)*(name+2)){
case (1275226) : // "kevin"
printf("hello %s.\n", name);
break;
case (1293980) : // "astro"
printf("welcome %s.\n", name);
break;
}
printf("%d",(int)*name * (int)*(name+1) * (int)*(name+2));
}
No, you cannot use the switch statement in C with the value of a string or character array. The closest alternative is to use some sort of data structure mapping strings to function pointers. The function pointer could be called after a string is used to look it up.
since the name is declared as a char type ,it would be better if you use "%c" instead of using "%s" inside the scanf() method.
You can use "hash-string.h" library that converts strings into hash code integer.
Create a header file and paste this code:
http://www.opensource.apple.com/source/gcc/gcc-5484/intl/hash-string.h
#include <stdio.h>
#include <stdlib.h>
#include "hash-string.h"
int main(){
char name[20];
printf("Enter a name: ");
scanf("%s",name);
unsigned long nameInt = hash_string(name);
switch(nameInt){
case 7458046 /* "kevin" */: { printf("Hello %s", name); break; }
default: { printf("You are not kevin"); }
}
printf("\n");
return 0;
}
Remember the rules while using switch statements.
Switch constraints
1. The controlling expression of a switch statement must have "integer type".
2. The expression of each case label shall be an integer constant expression and no two of
the case constant expressions in the same switch statement shall have the same value
after conversion. There may be at most one default label in a switch statement.
3. Any enclosed switch statement may have a default label or case constant expressions with values that duplicate case constant expressions in the enclosing switch statement.
If you are after performing specific actions for specific strings this implies you know the strings in advance. This in turn implies their number is limited, is countable, like for example a set of N commands:
const char * commands[] = {
"command-1",
"command-2",
...
"command-N"
}
To address those commands inside the array above from your code using a swtich you need to know their index, which is error prone. So number them, give them an ID:
enum Command_id {
NO_COMMAND,
COMMAND_1,
COMMAND_2,
//...
COMMAND_N,
};
Now put the two above together using a struct:
struct Command_info {
const char * command;
enum Command_id id;
} command_infos[] = {
{"", NO_COMMAND},
{"command-1", COMMAND_1},
{"command-2", COMMAND_2},
// ...
{"command-N", COMMAND_N},
};
Now you have nice mapping of strings and their related IDs. To be able to map from string to ID during runtime the mapping above needs to be searched. To do this in a efficient manner you want to us binary search. The C library proveids bsearch() for this. The only prerequsite is that the array to be searched need to sorted.
To sort use qsort() also proveid by the C library. For qsort() to work we you need a comparsion function:
int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
const struct Command_info * pCI1 = pvCI1;
const struct Command_info * pCI2 = pvCI2;
return strcmp(pCI1->command, pCI2->command);
}
Call qsort() like this
qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
Now as the array is sorted one can look it up using bsearch(). For "COMMAND-2" this would look like this:
... = bsearch(&(struct Command_info){"COMMAND-2", NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
Putting all this together could result in:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
enum Command_id {
NO_COMMAND,
COMMAND_1,
COMMAND_2,
//...
COMMAND_N,
};
struct Command_info {
const char * command;
enum Command_id id;
} command_infos[] = {
{"", NO_COMMAND},
{"command-1", COMMAND_1},
{"command-2", COMMAND_2},
// ...
{"command-N", COMMAND_N},
};
int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
const struct Command_info * pCI1 = pvCI1;
const struct Command_info * pCI2 = pvCI2;
return strcmp(pCI1->command, pCI2->command);
}
int main(int argc, char ** argv)
{
qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
{
enum Command_id command_id = NO_COMMAND;
struct Command_info * pCI = bsearch(&(struct Command_info){argv[1], NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
if (NULL == pCI)
{
printf("Command = '%s' is unknown\n", argv[1]);
}
else
{
printf("Command = '%s' --> ID = %d\n", pCI->command, pCI->id);
switch(command_id)
{
case COMMAND_1:
/* perform action on COMMAND 1 here */
break;
case COMMAND_2:
/* perform action on COMMAND 1 here */
break;
default:
/* unknow command, do nothing */
break;
}
}
}
}
Call it like:
./a.out command-1
giving:
Command = 'command-1' --> ID = 1
or:
./a.out command-bla
giving:
Command = 'command-bla' is unknown
or even
./a.out ""
giving:
Command = '' --> ID = 0