I'm learning pointers in C and i came across a confusion between pointers X struts X functions
The goal: creating two structs and mutate properties inside them.
The path I'm going: I am creating these two structs and then passing its memory addresses to the mutate function, the function then prints and mutates some properties of these structs.
Result I get:
1: The name of the struct created is nod being entirely printed and its of the wrong struct passed, and the life property is not properly changed and printed to the screen.
2: On the terminal I get "Segmentation Fault", not sure why but I'm pretty sure its something wrong I did.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int power;
int life;
char name[];
} Hero;
void attackHero(Hero *hero, int *power) {
(*hero).life = (*hero).life - *power;
printf("Damage: %d\n", *power);
printf("Attacked hero: %s\n", (*hero).name);
printf("Hero's remaining life: %d\n", (*hero).life);
};
int main () {
Hero flash;
flash.power = 250;
flash.life = 500;
strcpy(flash.name, "The Flash");
Hero batman;
batman.power = 380;
batman.life = 700;
strcpy(batman.name, "Batman arkham knight");
attackHero(&flash, &batman.power);
return 0;
}
Result printed to the terminal (Vscode + gcc):
Here is the warning that I get when I compile your original code:
1.c:25:2: warning: ‘__builtin_memcpy’ writing 10 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
25 | strcpy(flash.name, "The Flash");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.c:30:2: warning: ‘__builtin_memcpy’ writing 21 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
30 | strcpy(batman.name, "Batman arkham knight");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to use the flexible array then you have to allocate space for it like this:
int main () {
Hero *flash = malloc(sizeof(*flash) + sizeof("The Flash"));
flash->power = 250;
flash->life = 500;
strcpy(flash->name, "The Flash");
Hero *batman = malloc(sizeof(*flash) + sizeof("Batman arkham knight"));
batman->power = 380;
batman->life = 700;
strcpy(batman->name, "Batman arkham knight");
attackHero(flash, &batman->power);
free(flash);
free(batman);
}
Here there the resulting code refactored a bit, and I added a error check for malloc:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int power;
int life;
char name[];
} Hero;
Hero *createHero(int power, int life, const char *name) {
Hero *h = malloc(sizeof(*h) + strlen(name) + 1);
if(!h) {
printf("malloc failed\n");
exit(1);
}
h->power = power;
h->life = life;
strcpy(h->name, name);
return h;
}
void attackHero(Hero *hero, int power) {
hero->life -= power;
printf(
"Damage: %d\n"
"Attacked hero: %s\n"
"Hero's remaining life: %d\n",
power,
hero->name,
hero->life
);
};
int main(void) {
Hero *flash = createHero(250, 500, "The Flash");
Hero *batman = createHero(380, 700, "Batman arkham knight");
attackHero(flash, batman->power);
free(flash);
free(batman);
}
Alternatively use a fixed array (char [64] as suggested by #Diego) or a char * and allocate space to it. The former only needs 2 lines of code change from the original:
// largest name in use
#define NAME_LEN sizeof("Batman arkham knight")
typedef struct {
int power;
int life;
char name[NAME_LEN];
} Hero;
Whole lotta malloc() going on. Since the hero’s names are string literals (and assuming they don’t change), just change name[]; to const char *name in the structure and initialize via simple assignment:
flash.name = "The Flash";
batman.name = "Batman arkham knight";
No worries about malloc() failures, name sizes or free() requirements.
Related
I've had this problem for the last two hours and I can't understand what's happening. I expect it to print this
ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM
COPYRIGHT 2075-2077 ROBCO INDUSTRIES
-Server 6-
But instead it displays this
ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM
COPYRIGHT Testing testing 123
I have no clue why this is happening but hopefully you will be able to help me. (If you want to know what this is for it's a Fallout Terminal Emulator). Just ask if you nned any more details. Thanks!
It's being compiled like this if you need to know
gcc test.c configParser.c -lconfig
test.c
#include <stdio.h>
#include "robco.h"
int main() {
struct config_struct config;
config = getConfig("test_config.cfg");
printf("%s", config.banner);
return 0;
}
configParser.c
#include <stdio.h>
#include <libconfig.h>
#include <string.h>
#include "robco.h"
int cap(int num, int cap) {
return (num > cap) ? cap : num;
}
struct config_struct getConfig(const char *filename)
{
config_t cfg;
config_setting_t *root, *menu, *options, *option;
// Read the file. If there is an error, report it and exit.
config_init(&cfg);
config_read_file(&cfg, filename);
root = config_root_setting(&cfg);
// Get the banner from the config file if it exists, if not use the default set in robco.h
const char *banner;
if (! config_setting_lookup_string(root, "banner", &banner) ) {
banner = DEFAULT_BANNER;
}
// Create the config struct and fill in the banner
struct config_struct config;
strcpy(config.banner, banner);
// Get the menu
menu = config_lookup(&cfg, "menu");
// If it can't fetch the menu for any reason return -1
if(! menu) {
return;
}
// Get the options
options = config_setting_get_member(menu, "options");
if(! options) {
return;
}
// Get number of options
config.menu.num_options = cap(config_setting_length(options), MAX_OPTIONS);
// Get the title. If it doesn't exist use the default
const char *title;
if (! config_setting_lookup_string(menu, "title", &title) ) {
title = DEFAULT_TITLE;
}
strcpy(config.menu.title, title);
// Loop through and get the text for all the options
for(int i = 0; i < config.menu.num_options; ++i)
{
option = config_setting_get_elem(options, i);
const char *text;
config_setting_lookup_string(option, "text", &text);
strcpy(config.menu.options[i].text, text);
}
return config;
}
robco.h
#define MAX_STRING_LENGTH 52
#define MAX_OPTIONS 5
#define DEFAULT_BANNER "ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM\nCOPYRIGHT 2075-2077 ROBCO INDUSTRIES\n-Server 6-"
#define DEFAULT_TITLE "-=- TEST TITLE -=-"
struct option_struct {
char text[MAX_STRING_LENGTH];
};
struct menu_struct {
struct option_struct options[MAX_OPTIONS];
int num_options;
int selected;
char title[MAX_STRING_LENGTH];
};
struct config_struct {
char banner[MAX_STRING_LENGTH];
struct menu_struct menu;
};
void printCenter(char msg[], int startRow);
void printMenuOption(char msg[], int startRow);
void drawMenu(struct menu_struct menu, int startRow);
void init_graphics();
struct config_struct getConfig(const char *filename);
test_config.cfg
menu: {
title: "Super Secret Valve Control Panel";
options: (
{
text: "Testing testing 123";
},
{
text: "THE SUN IS A DEADLY LASER";
}
);
};
I bet your MAX_STRING_LENGTH is too little and that you don't test for lengths. You must use strncpy and then don't forget to set the terminating null, which strncpy doesn't do.
You must also turn the warnings of your compiler on. I see struct config_struct getConfig but in that function you do some returns without a return value. The compiler should warn about that.
Your default banner text is longer than MAX_STRING_LENGTH, so when you copy it to config.banner you write past the end of the array, leading to undefined behavior.
Make sure all your buffers are large enough to store the longest string you expect (accounting for the terminator), or truncate strings to the length of the buffer, or use dynamic memory and size the buffers as you need to.
I'm trying to optimize access to some jump tables I have made, they are as follows:
int (*const usart_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[USART_READ_WRITE_CLEAR])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
As you can see, the functions are for accessing a usart peripheral on a hardware level and are arranged in the table in the order of read/write/clear.
What I am attempting to do is have another jump table of jump tables, this way I can either run through initializing all the usart's registers in startup or simply change a single register later if desired.
i.e.
<datatype> (*usart_peripheral_table[<number of jump tables>])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
This way I can expose that table to my middleware layer, which will help maintain a standard across changing HALs, and also I can use a define to index this table i.e.
fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);
As you may have already guessed, I am struggling to figure out how to construct this table. I figured it is one of two things:
Another simple array of pointers, as even a jump table itself is just an array of pointers. Hence my initialization would be:
const int* (*usart_peripheral_table[<number of jump tables])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
However this doesn't seem to be working. Then I thought:
An array of pointers to pointers. So I tried all kinds of combos:
const int**(*usart_perip...
const int**(usart_perip...
const int** (*usart_peripheral_table[<number of jump tables])() =
{&usart_ctrl_table, &usart_frame_table[0], usart_trig_ctrl_table};
Nothing seems to work. Do I need to store the address of the lower jump tables in yet another pointer before assigning that variable to a pointer-to-pointer array? i.e.
int* fn_ptr = usart_ctrl_table;
<dataytype>(*const usart_periph[<number>])() = {fn_ptr};
Thanks in advance, any help would be greatly appreciated.
MM25
EDIT:
const int** (*const peripheral_table[1])() =
{&usart_ctrl_table[0]};
const int** (*const peripheral_table[1])() =
{usart_ctrl_table};
The above both give the error "initialization from incomaptible pointer type", as do all other combinations I have tried
You might find that defining a typedef for your function pointers makes your code easier to read and maintain (although I’ve seen people recommend against it too):
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
uart_ctl_func uart_ctl_jump_table[][UART_RWC] = {
{ uart_read, uart_write, uart_clear },
{ uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_jump_table[0][1](); // Write.
uart_ctl_jump_table[1][0](); // Read.
uart_ctl_jump_table[1][2](); // Clear.
return EXIT_SUCCESS;
}
The next step might be to make the jump table a struct so you end up writing Uart_ctl_table.frame.read(), or to at least define an enum for the constants.
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
typedef struct {
uart_ctl_func read;
uart_ctl_func write;
uart_ctl_func clear;
} uart_ctl_set_t;
typedef struct {
uart_ctl_set_t ctrl;
uart_ctl_set_t frame;
uart_ctl_set_t trig;
} uart_ctl_table_t;
const uart_ctl_table_t uart_ctl_table = {
.ctrl = { uart_read, uart_write, uart_clear },
.frame = { uart_read, uart_write, uart_clear },
.trig = { uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_table.ctrl.write(); // Write.
uart_ctl_table.frame.read(); // Read.
uart_ctl_table.trig.clear(); // Clear.
return EXIT_SUCCESS;
}
Just add a * like you added [] when defining an array.
int zg_usartCtrlRead();
int zg_usartCtrlWrite();
int zg_usartCtrlClr();
int zg_usartFrameRead();
int zg_usartFrameWrite();
int zg_usartFrameClr();
int zg_usartTrigctrlRead();
int zg_usartTrigctrlWrite();
int zg_usartTrigctrlClr();
int (*const usart_ctrl_table[])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
int (* const * const usart_peripheral_table[])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
Usage:
usart_peripheral_table[1][2](5, 1, 3, 5, 6);
Btw, an empty parameter list on function declaration () means unspecified number and type of arguments. Do (void) if you want no arguments passed to your function.
This:
const int* (*usart_peripheral_table[<number of jump tables])();
Is an array of functions pointers that take unspecified number of arguments and return a pointer to constant integer.
This:
const int** (*usart_peripheral_table[<number of jump tables])()
Is an array of function pointers that take unspecified number of arguments and return a pointer to a pointer to a constant integer.
You can also go with a 2D array:
int (* const usart_peripheral_table_2d[][3])() = {
{
zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr,
}, {
zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr,
}, {
zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr,
},
};
But maybe you want to write accessor functions that will return a pointer to an array of functions. Nothing simpler!
#include <stddef.h>
int (*usart_ctrl_table_get(size_t idx))() {
return usart_ctrl_table[idx];
}
int (*usart_frame_table_get(size_t idx))() {
return usart_frame_table[idx];
}
int (*usart_trig_ctrl_table_get(size_t idx))() {
return usart_trig_ctrl_table[idx];
}
int (* const (* const usart_peripheral_table_indirect[])(size_t))() = {
usart_ctrl_table_get,
usart_frame_table_get,
usart_trig_ctrl_table_get,
};
Usage sample:
int main() {
usart_peripheral_table_indirect[2](1)();
}
I'm trying to make a game that requires dynamically sized arrays in C but my code isn't working even though identical code works in another one of my programs.
Here are my #includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SwinGame.h" //API for graphics, physics etc
#include <math.h>
Here are my typedefs for the relevant structs used:
typedef struct position_data
{
double x;
double y;
} position_data;
typedef enum enemy_type_data {CIRCLE, TRIANGLE, SQUARE} enemy_type_data;
typedef struct enemy_data
{
position_data location;
enemy_type_data type;
bitmap bmp;
double health;
double speed;
int path_to;
} enemy_data;
typedef struct enemy_data_array
{
int size;
enemy_data *data;
} enemy_data_array;
Here is the function to add an element to the array:
void add_enemy(enemy_data_array *enemies)
{
enemy_data *new_array;
enemies->size++;
new_array = (enemy_data *)realloc(enemies->data, sizeof(enemy_data) * enemies->size);
if (new_array) //if realloc fails (ie out of memory) it will return null
{
enemies->data = new_array;
// enemies->data[enemies->size - 1] = read_enemy_data();
printf("Enemy added successfully!\n");
}
else
{
printf("FAILED. Out of Memory!\n");
enemies->size--;
}
}
And here is my function call and variable declaration in the main procedure:
int main()
{
path_data my_path[41];
enemy_data_array enemies;
enemies.size = 0;
add_enemy(&enemies);
}
Why isn't this working?
You invoked undefined behavior by passing indeterminate value enemies->data in uninitialized variable having automatic storage duration. Initialize it before using add_enemy().
int main()
{
path_data my_path[41];
enemy_data_array enemies;
enemies.size = 0;
enemies.data = 0; /* add this line */
add_enemy(&enemies);
}
0 is a null pointer constant and can safely be converted to pointer NULL. Unlike NULL, 0 will work without including any headers. Of course you can use enemies.data = NULL; with proper header included.
#2501's explanation is completely correct. Another solution is to change your implementation of add_enemy() to something like this:
void add_enemy(enemy_data_array *enemies)
{
enemy_data *new_array;
// check if size was non-zero
if (enemies->size++)
{
new_array = (enemy_data *)realloc(enemies->data, sizeof(enemy_data) * enemies->size);
}
// start new allocation
else
{
new_array = (enemy_data *)alloc(sizeof(enemy_data) * enemies->size);
}
if (new_array) //if (re)alloc fails (ie out of memory) it will return null
{
enemies->data = new_array;
// enemies->data[enemies->size - 1] = read_enemy_data();
printf("Enemy added successfully!\n");
}
else
{
printf("FAILED. Out of Memory!\n");
enemies->size--;
}
}
If fails because you haven't cleared the content of "enemies". Since it is a stack variable, it will contain whatever garbage data is on the stack.
set enemies.data to NULL in the main function and try it again.
I have written a straightforward C code that uses an engine to run two different algorithms depending on user input. It uses function pointers to the algorithm methods and objects. There is a nasty memory bug somewhere that I can not track down, so maybe I am allocating memory in the wrong way. What is going wrong?
Below is (the relevant parts of) a minimal working example of the code.
main.c
#include "engine.h"
int main()
{
char *id = "one";
Engine_t eng;
Engine_init(&eng);
Engine_select_algorithm(eng, id);
Engine_run(eng);
}
engine.h
typedef struct _Engine *Engine_t;
engine.c
#include "engine.h"
#include "algorithm_one.h"
#include "algorithm_two.h"
typedef struct _Engine
{
void *p_algorithm;
void (*init)(Engine_t);
void (*run)(Engine_t);
} Engine;
void Engine_init(Engine_t *eng)
{
*eng = malloc(sizeof(Engine));
(*eng)->p_algorithm = NULL;
}
void Engine_select_algorithm(Engine_t eng, char *id)
{
if ( strcmp(id, "one") == 0 )
{
eng->init = Algorithm_one_init;
eng->run = Algorithm_one_run;
}
else if ( strcmp(id, "two") == 0 )
{
eng->init = Algorithm_two_init;
eng->run = Algorithm_two_run;
}
else
{
printf("Unknown engine %s.\n", id); exit(0);
}
eng->init(eng);
}
void Engine_run(Engine_t eng)
{
eng->run(eng);
}
void Engine_set_algorithm(Engine_t eng, void *p)
{
eng->p_algorithm = p;
}
void Engine_get_algorithm(Engine_t eng, void *p)
{
p = eng->p_algorithm;
}
algorithm_one.h
typedef struct _A_one *A_one_t;
algorithm_one.c
#include "engine.h"
#include "algorithm_one.h"
typedef struct _A_one
{
float value;
} A_one;
void Algorithm_one_init(Engine_t eng)
{
A_one_t aone;
aone = malloc(sizeof(A_one));
aone->value = 13.0;
//int var = 10;
Engine_set_algorithm(eng, &aone);
}
void Algorithm_one_run(Engine_t eng)
{
A_one_t aone;
Engine_get_algorithm(eng, &aone);
printf("I am running algorithm one with value %f.\n", aone->value);
// The code for algorithm one goes here.
}
The code for algorithm_two.h and algorithm_two.c are identical to the algorithm one files.
There must be a memory bug involved, because the code runs as given, but if I uncomment the
//int var = 10;
line in algoritm_one.c the code crashes with a segmentation fault.
You pass the wrong thing to Engine_set_algorithm. You are passing the address of a local variable rather than the address of the algorithm. You need to write:
Engine_set_algorithm(eng, aone);
And also Engine_get_algorithm is wrong. You are passed a pointer by value and modify that pointer. So the caller cannot see that modification. You need it to be:
void Engine_get_algorithm(Engine_t eng, void **p)
{
*p = eng->p_algorithm;
}
I think your code would be easier if you defined a type to represent an algorithm. That type would be just a void*, but it would make the code much easier to read. What's more, I would make Engine_get_algorithm return the algorithm.
algorithm Engine_get_algorithm(Engine_t eng)
{
return eng->p_algorithm;
}
void Engine_set_algorithm(Engine_t eng, algorithm alg)
{
eng->p_algorithm = alg;
}
I have a definite set of strings and its corresponding numbers:
kill -> 1
live -> 2
half_kill -> 3
dont_live -> 4
List is of 30 such strings and their number mapping.
If user enters "kill", I need to return 1 and if he enters "dont_live" I need to return 4.
How should I achieve this in c program? I am looking for an efficient solution because this operation needs to be done 100s of times.
should I put them in #define in my .h file?
Thanks in advance.
Sort your table, and use the standard library function bsearch to perform a binary search.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct entry {
char *str;
int n;
};
/* sorted according to str */
struct entry dict[] = {
"dont_live", 4,
"half_kill", 3,
"kill", 1,
"live", 2,
};
int compare(const void *s1, const void *s2)
{
const struct entry *e1 = s1;
const struct entry *e2 = s2;
return strcmp(e1->str, e2->str);
}
int
main (int argc, char *argv[])
{
struct entry *result, key = {argv[1]};
result = bsearch(&key, dict, sizeof(dict)/sizeof(dict[0]),
sizeof dict[0], compare);
if (result)
printf("%d\n", result->n);
return 0;
}
Here's what you get when you run the program.
$ ./a.out kill
1
$ ./a.out half_kill
3
$ ./a.out foo
<no output>
PS: I reused portions of sidyll's program. My answer should now be CC BY-SA compliant :p
A possible solution:
#include <stdio.h>
#include <string.h>
struct entry {
char *str;
int n;
};
struct entry dict[] = {
"kill", 1,
"live", 2,
"half_kill", 3,
"dont_live", 4,
0,0
};
int
number_for_key(char *key)
{
int i = 0;
char *name = dict[i].str;
while (name) {
if (strcmp(name, key) == 0)
return dict[i].n;
name = dict[++i].str;
}
return 0;
}
int
main (int argc, char *argv[])
{
printf("enter your keyword: ");
char s[100]; scanf("%s", s);
printf("the number is: %d\n", number_for_key(s));
return 0;
}
Here's one approach:
int get_index(char *s)
{
static const char mapping[] = "\1.kill\2.live\3.half_kill\4.dont_live";
char buf[sizeof mapping];
const char *p;
snprintf(buf, sizeof buf, ".%s", s);
p = strstr(mapping, buf);
return p ? p[-1] : 0;
}
The . mess is to work around kill being a substring of half_kill. Without that issue you could simply search for the string directly.
If it is a very short list of strings then a simple block of ifs will be more than sufficient
if (0 == strcmp(value, "kill")) {
return 1;
}
if (0 == strcmp(value, "live")) {
return 2;
}
...
If the number approach 10 I would begin to profile my application though and consider a map style structure.
if you have a fixed set of strimgs, you have two options: generate a perfect hashing function (check gperf or cmph) or create a trie so that you never have to check charcters more than once.
Compilers usually use perfect hashes to recognize a language keyword, in your case I would probably go with the trie, it should be the fastest way (but nothing beats direct measurement!)
Is it really a bottleneck? You should worry about efficiency only if the simple solution proves to be too slow.
Having said that, possible speed improvements are checking the lengths first:
If it's 4 characters then it could be "kill" or "live"
If it's 9 characters then it could be "half_kill" or "dont_live"
or checking the first character in a switch statement:
switch (string[0]) {
case 'k':
if (strcmp(string, "kill") == 0)
return 1;
return 0;
case 'l':
...
default:
return 0;
}
Use hashmap/ hashtable i think this would be the best solution.
Can you use an Enumunerator?
int main(void) {
enum outcome { kill=1, live, half_kill, dont_live };
printf("%i\n", kill); //1
printf("%i\n", dont_live); //4
printf("%i\n", half_kill); //3
printf("%i\n", live); //2
return 0;
}
Create a list of const values:
const int kill = 1;
const int live = 2;
const int half_kill = 3;
etc