Macro for doing a switch on strings - c

Outside of using a hash function, I'd like to write a basic mapping of a key/value lookup of a few movie-credits related items. Does the following macro seem like an acceptable way to do it?
#include <stdio.h>
#include <string.h>
#define TOMAP(input_str, output_buf, from, to) \
if (strcmp(input_str, from) == 0) \
strcpy(output_buf, to)
void map_imdb_position(const char* pos, char output[])
{
TOMAP(pos, output, "Director", "director");
TOMAP(pos, output, "Writer", "scribe");
}
int main(void) {
char position[20];
map_imdb_position("Director", position);
printf("Director->%s\n", position);
}
If not, what might be a better approach to doing a sort of switch statement on a string comparison?

As suggested in the comments a cleaner way to do this would be with a map of credits in a function, for example:
#include <stdio.h>
#include <string.h>
typedef struct map {
char from[20];
char to[20];
} Map;
void map_imdb_position(const char* credit, char output[])
{
static Map credits[] = {
{"Director", "director"},
{"Writer", "scribe"}
};
for (int i=0; i < sizeof(credits)/sizeof(*credits); i++) {
if (strcmp(credit,credits[i].from) == 0) {
strcpy(output, credits[i].to);
break;
}
}
printf("%s --> %s\n", credit, output);
}
int main(void) {
char position[20];
map_imdb_position("Director", position);
map_imdb_position("Writer", position);
}
Working example: https://onlinegdb.com/Sk_t76aQ_

Side note: I was working on this solution but Carl already came up with a similar one.
But, I prefer to use the ptr->field syntax and to have an end-of-table sentinel at the end (vs. the sizeof construct to get the count).
And, I think designated initializers when constructing the table make things more readable [especially if more fields need to be added to the struct].
So, here's my version:
#include <stdio.h>
#include <string.h>
typedef struct {
const char *from;
const char *to;
} mapimdb_t;
mapimdb_t mapimdb[] = {
{ .from = "Director", .to = "director" },
{ .from = "Writer", .to = "scribe" },
// ...
{ .from = NULL }
};
void
map_imdb_position(const char *pos, char *output)
{
for (const mapimdb_t *map = mapimdb; map->from != NULL; ++map) {
if (strcmp(pos,map->from) == 0) {
strcpy(output,map->to);
break;
}
}
}
void
dotest(const char *from,char *out)
{
map_imdb_position(from,out);
printf("dotest: %s->%s\n",from,out);
}
int
main(void)
{
char position[20];
dotest("Director", position);
dotest("Writer", position);
}

X macros can be used:
#include <stdio.h>
#include <string.h>
#define STR_LIST \
X("Director", "director") \
X("Writer", "scribe")
void map_imdb_position(const char* pos, char output[])
{
#define X(from, to) \
if (strcmp(pos, from) == 0) \
{ strcpy(output, to); return; } // "return" was missing?
STR_LIST
#undef X
}
int main(void) {
char position[20];
map_imdb_position("Director", position);
printf("Director->%s\n", position);
}

Related

Some issues with "read access violation"

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
typedef struct {
char name[128], code[128];
} info;
info db[3];
info* data=db;
void find (const char *code, int size, ...) {
bool mismatch = true;
va_list arg;
va_start(arg,size);
while (size-- > 0) {
data = va_arg(arg,info*);
printf("%s", data->code);
if (!strcmp(data->code,code))
{
printf("%s [id:%s]\n",data->name,data->code), mismatch = false;
}
}
if (mismatch) printf("No data available!");
return;
}
int main (int argc, char *argv[], char *envp[]) {
const char *spec[] = {
"Physics of Elementary Particles",
"Physics of Hign Energy",
"Low-level Programming"
};
const char *code[] = {
"2396","0812", "0773"
};`enter code here`
for (int count = 0; count < 3; ++count) {
strncpy(db[count].name,spec[count],128);
strncpy(db[count].code,code[count],128);
}
find("0812",3,db[0],db[1],db[2]);
return 0;
}
After running it says "read access violation", although I hope everything is correct, it happens after function "va_arg(arg, info*)". Is it some troubles with stack or decrypting?
The problem is in the function call:
find("0812",3,db[0],db[1],db[2]);
The variadic argument that you're passing in are of type info. However, when you retrieve them with va_arg you're looking for a info *. These don't match up.
You want to pass in the address of each array member.
find("0812",3,&db[0],&db[1],&db[2]);
Also, you need to call va_end at the bottom of find before you return.

I want to sort my struct by alphabetical order, but if i do the sort, my program doesn't give any output

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct kezdo
{
int mennyi;
char betu;
}KEZDO;
int main(int argc, char* argv[])
{
int j;
int i;
int db=0;
int volt=0;
char sajt[22];
FILE* f=fopen(argv[1], "r");
if(f==NULL)
{
fprintf(stderr, "Hiba a fajl megnyitasaban!");
}
int k = 20;
KEZDO t[k];
KEZDO tmp;
for(i=0;i<k;i++)
{
t[i].mennyi = 0;
}
while(fgets(sajt,22,f)!=0)
{
if(sajt[strlen(sajt)-1] == '\n')
{
sajt[strlen(sajt)-1] = '\0';
}
for(i=0;i<k;i++)
{
if(t[i].betu == toupper(sajt[0]))
{
t[i].mennyi++;
volt=1;
}
}
if(volt==0)
{
t[db].betu = toupper(sajt[0]);
t[db].mennyi++;
db++;
}
else
{
volt = 0;
}
}
for(i=0;i<db;i++)
{
printf("%c: %d\n", t[i].betu, t[i].mennyi);
}
return 0;
}
I tried strcmp and stricmp but neither worked. I tried to fully change the struct by sorting the struct properties. When the struct properties are sorted it doesn't work, but it worked before in a non-sorted order. What is preventing output when the struct properties are sorted?
As i can see in your code, you want to sort on char betu. One way to sort structures is via qsort but that'd require comparator function stated below:
int compare(const void *void_a, const void *void_b)
{
const KEZDO *a = void_a;
const KEZDO *b = void_b;
return (a->betu) < (b->betu);
}
//Perform sort like this;
qsort((void *) &t, db, sizeof(KEZDO) , compare );
Moreover, qsort is in #include <stdlib.h>

merging of text

Can you please help me with merging of two texts into one using just only stdio.h and stdlib.h? The result should be HelloWorld.
So far, I have the following, but there is a mistake somewhere.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char *spojeni(char *t1, char *t2)
{
char pole_spolecne[10];
for (*t1 = 0; *t1 < 5; t1++)
{
pole_spolecne[*t1] = *t1;
}
for (*t2 = 0; *t2 < 10; t2++)
{
pole_spolecne[*t2 + 5] = *t2;
}
return pole_spolecne;
}
int main()
{
char pole1[] = { "Hello" };
char pole2[] = { "World" };
printf("%s\n", spojeni(pole1, pole2));
system("pause");
return 0;
}
My new solution, but it returns an error at the end:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char *spojeni(char *t1, char *t2)
{
char pole_cele[20];
char *p_pole_cele;
p_pole_cele = t1;
strcat(p_pole_cele, t2);
return p_pole_cele;
}
int main()
{
char pole1[] = { "Hello" };
char pole2[] = { "World" };
char *p_pole1;
char *p_pole2;
p_pole1 = pole1;
p_pole2 = pole2;
printf("%s\n)", spojeni(p_pole1, p_pole2));
system("pause");
return 0;
}
Finally, this change of function helped:
char *spojeni(char *t1, char *t2)
{
char pole_cele[20];
char *p_pole_cele;
p_pole_cele = (char *)malloc(10);
strcpy(p_pole_cele, t1);
p_pole_cele = (char *)realloc(p_pole_cele, 20);
strcat(p_pole_cele, t2);
return p_pole_cele;
}
I am not quite sure how to answer this, as this is clearly a teaching exercise, and, to be blunt, the code given shows a lack of understanding of pointers. And pointers is a topic better taught in person than via a web-site comment.
A few hints, though:
Think very clearly about pointers, what they are pointing to, and what makes them different from array indices.
Draw diagrams to visualize what you're doing.
Your exercise can be solved using calloc(), strlen() and strcpy().

Allocating a dynamic 2D array

Everything seems to work fine while dynamically creating the array
but core dumped while trying to print it backwards.
It managed to print only the last string and then segmentation fault.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void init_array(void ***pt, int *ptlen) {
*pt=NULL;
*ptlen=0;
}
void trim_array(void ***pt, int *ptlen, int len) {
*pt=(void**)realloc(*pt, len*sizeof(void*));
*ptlen=len;
}
void write_array(void ***pt, int *ptlen, int pos, void *v) {
if (pos >= *ptlen)
trim_array(pt, ptlen, pos+1);
*pt[pos]=v;
}
void *read_array(void ***pt, int *ptlen, int pos) {
return(*pt[pos]);
}
void destroy_array(void ***pt, int *ptlen) {
trim_array(pt, ptlen, 0);
*pt=NULL;
}
int main(int argc, char *argv[]) {
void **t;
int tlen;
void ***pt = &t;
int *ptlen = &tlen;
char s[256],*p; int i;
init_array(pt, ptlen);
i = 0;
do {
printf("give name:\n");
scanf("%255s",s);
write_array(pt, ptlen, i, (void*)strdup(s));
i++;
} while (strcmp(s,"end"));
for (--i; i>=0; i--) {
p = (char*)read_array(pt, ptlen, i);
printf("%s\n",p);
free(p);
}
destroy_array(pt, ptlen);
return(0);
}
The [] operator has a higher precedence than the * operator. You need to change:
*pt[pos]
to:
(*pt)[pos]
in both places where it occurs.
This error is a direct result of writing almost deliberately confusing code with runaway indirection. You'd save yourself a lot of trouble and make things much easier if you wrapped a lot of this stuff in a struct and created some proper interface functions for it.
Something like this would be a bit better form (although "array" is not really a great name for this data structure):
main.c:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "array.h"
#define MAX_BUFFER_LEN 255
int main(void) {
Array myarray = array_init(10, true);
/* Loop for input until user enters "end" */
char buffer[MAX_BUFFER_LEN];
while ( true ) {
printf("Give name: ");
fflush(stdout);
/* Get input and remove trailing '\n' if necessary */
fgets(buffer, MAX_BUFFER_LEN, stdin);
size_t last = strlen(buffer) - 1;
if ( buffer[last] == '\n' ) {
buffer[last] = '\0';
}
/* Terminate loop on "end" without adding to array... */
if ( !strcmp(buffer, "end") ) {
break;
}
/* ...or append input to array and continue loop */
array_append(myarray, strdup(buffer));
};
/* Output contents of array */
size_t n = array_size(myarray);
for ( size_t i = 0; i < n; ++i ) {
char * data = array_getdata(myarray, i);
printf("%zu: %s\n", i + 1, data);
}
/* Clean up and exit */
array_destroy(myarray);
return EXIT_SUCCESS;
}
array.h:
#ifndef ARRAY_TYPE_H
#define ARRAY_TYPE_H
#include <stdbool.h>
typedef struct array_type * Array; /* Opaque type for user */
Array array_init(const size_t capacity, const bool free_on_delete);
void array_append(Array array, void * data);
size_t array_size(const Array array);
void * array_getdata(Array array, const size_t index);
void array_deletetop(Array array);
void array_destroy(Array array);
#endif /* ARRAY_TYPE_H */
array.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "array.h"
/* Struct definition is visible only to implementation */
struct array_type {
void ** elements;
size_t capacity;
size_t top;
bool free_on_delete;
};
/* Static functions used by the implementation */
static bool array_isfull(Array array) {
return (array->top + 1) == array->capacity;
}
static void array_resize(Array array, const size_t new_capacity) {
array->capacity = new_capacity;
array->elements = realloc(array->elements,
array->capacity * sizeof (*array->elements));
if ( array->elements == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
}
/* Interface functions */
Array array_init(const size_t capacity, const bool free_on_delete) {
struct array_type * new_array = malloc(sizeof *new_array);
if ( new_array == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
new_array->elements = malloc(capacity * sizeof (*new_array->elements));
if ( new_array->elements == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
new_array->capacity = capacity;
new_array->top = 0;
new_array->free_on_delete = free_on_delete;
return new_array;
}
void array_append(Array array, void * data) {
if ( array_isfull(array) ) {
array_resize(array, array->capacity * 2);
}
array->elements[array->top++] = data;
}
size_t array_size(const Array array) {
return array->top;
}
void * array_getdata(Array array, const size_t index) {
return array->elements[index];
}
void array_deletetop(Array array) {
if ( array->free_on_delete ) {
free(array->elements[array->top - 1]);
}
array->elements[--array->top] = NULL;
}
void array_destroy(Array array) {
while ( array->top > 0 ) {
array_deletetop(array);
}
free(array->elements);
free(array);
}
Sample output:
paul#local:~/src/c/scratch/array$ ./array
Give name: Dave Dee
Give name: Dozy
Give name: Beaky
Give name: Mick
Give name: Titch
Give name: end
1: Dave Dee
2: Dozy
3: Beaky
4: Mick
5: Titch
paul#local:~/src/c/scratch/array$

Replacing one string with other in C

I have a string
{"status":true}
I want to replace &quot with ". I tried several string operations, but they're not working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace (char *this, char *withthat, char *inthis) {
char *where = inthis;
if(strlen(withthat)>strlen(this)) {
fprintf(stderr, "replace can only shrink\n");
exit(EXIT_FAILURE);
}
while ((where = strstr(where, this))) {
memcpy(where, withthat, strlen(withthat));
memmove(where+strlen(withthat),where+strlen(this), strlen(where+strlen(this))+1);
}
return inthis;
}
int main(void) {
char string[] = "{"status":true}";
printf("%s\n", replace(""", "\"", string));
return 0;
}
Output:
{"status":true}

Resources