I want to store a string to a char array inside a structure and when I access the char array I want the result to be displayed along with the value from the global variable errCode. When I access the errDesc member of the structure then I want the result to be "Error detected with error code 0xA0B0C0D0", but since using strcpy copies the string as it is I am getting a result "Error detected with error code %08lx" . Here is a sample code which replicates my issue:
int errCode = 0xA0B0C0D0;
void function(errpacket* ptr, int a, char* errString, ...);
typedef struct{
int err;
char errDesc;
}errpacket;
int main(){
errpacket* a;
void function(a, 10, "Error detected with error code %08lx", errCode);
return 0;
}
void function(errpacket* ptr, int a, char* errString, ...){
ptr->err = a;
strcpy(&ptr->errDesc, errString);
}
If my implementation is incorrect, please suggest me a way to do what I intend to. Also please point out the mistakes in the above code.
you have to typedef the struct errpacket before declaration of function(...)
Variable a in function main() is only a pointer. You'll get a segmentation fault inside function if you try to write to an uninitialized pointer.
The member errDesc will only hold ONE char, not a string or char array.
Try this...
int errCode = 0xA0B0C0D0;
typedef struct {
int err;
char* errDesc;
} errpacket;
void function (errpacket* ptr, int a, char* errString, ...);
int main () {
errpacket a;
function(&a, 10, "Error detected with error code %08lx", errCode);
return 0;
}
void function (errpacket* ptr, int a, char* errString, ...) {
ptr->err = a;
ptr->errDesc = strdup( errString);
}
try this fix:
#include <stdarg.h> //to be added for vsprintf use
int errCode = 0xA0B0C0D0;
void function(errpacket* ptr, int a, char* errString, ...);
typedef struct{
int err;
char *errDesc;
}errpacket;
int main(){
errpacket a; //you need allocate memory if you use a pointer here
void function(&a, 10, "Error detected with error code %08lx", errCode);
return 0;
}
void function(errpacket* ptr, int a, char* errString, ...){
ptr->err = a;
ptr->errDesc = malloc(strlen(errString)+1);
memset(ptr->errDesc, 0, strlen(errString)+1);
/*if(ptr->errDesc != NULL)
{
strcpy(ptr->errDesc, errString);
}*/
// use like following if you want use a formatted string
if(ptr->errDesc != NULL)
{
va_list args;
va_start (args, errString);
vsprintf (ptr->errDesc, errString, args);
va_end (args);
}
}
You can't use a single char variable to hold an entire string.
What you can do is declare errDesc to be either an array of fixed length (if you know the maximum number of characters that an error description can contain), or a pointer that is allocated dynamically with malloc and later freed with free.
Array case:
#define MAX_ERR_STRING_SIZE 500
typedef struct
{
int err;
char errDesc[MAX_ERR_STRING_SIZE];
} errpacket;
// You can now use strcpy() to copy to errpacket::errDesc assuming none of the error strings exceed MAX_ERR_STRING_SIZE
Dynamic memory:
typedef struct
{
int err;
char *errDesc;
} errpacket;
// Take note of the new parameter: int errStringLength,
void function(errpacket* ptr, int a, char* errString, int errStringLength, ...){
ptr->err = a;
ptr->errDesc = malloc((errStringLength + 1) * sizeof(char));
if(ptr->errDesc == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(&ptr->errDesc, errString);
}
After you are done using ptr you will need to call free(ptr->errDesc); to de-allocate the string.
I don't think you really want a function with variable arguments, like printf. The solution below just expects the arguments you use in the end. Note that I do not use a user-supplied format string; that is considered a security risk. I also used snprintf (instead of the simple sprintf) in order to protect against error messages which are longer than the array size in the struct. The array size is a define so that it can be changed easily.
Specific fixes:
Proper declaration order (define the struct type before it's used)
Define an actual error packet object (and not just an uninitialized pointer to one)
Provide actual memory in the error packet for the message
Provide a print function for error packets
Do not let the user code specify printf formats; print user supplied strings with a length protected %s format specifier.
Do not use a variable argument function (whose excess arguments were not evaluated anyway); just declare the needed arguments explicitly.
.
#include<stdio.h>
int errCode = 0xA0B0C0D0;
#define MAX_ERRDESC_LEN 80 // avoid literals
typedef struct{
int err;
char errDesc[MAX_ERRDESC_LEN]; // provide actual space for the message
}errpacket;
void printErrPack(FILE *f, errpacket *ep){
fprintf(f, "Error packet:\n");
fprintf(f, " err = 0x%x:\n", ep->err);
fprintf(f, " desc = ->%s<-\n", ep->errDesc);
}
// Standard function with fixed argument count and types
void function(errpacket* ptr, int errNo, char* errString, int errCodeArg){
ptr->err = errNo;
// snprintf "prints" into a string
snprintf( ptr->errDesc, // print destination
MAX_ERRDESC_LEN, // max length, no buffer overflow
"%s with error code %x", // do not use user string as format
errString, // user supplied string, printed via %s
errCodeArg );
}
int main(){
errpacket a; // define an actual object, not a pointer
// pass the address of the object a
function(&a, 0xdead, "Error detected ", errCode);
printErrPack(stdout, &a);
return 0;
}
Related
Basically I have a struct which stores my general program settings. I read in a config with the callback function to get the corresponding value, but I can't write it to the struct. I've tried everything from memcpy over strcpy to dereferencing the char pointer, but every time the char in the struct stays empty. The passed string contains only one char, I checked that multiple times. Also if I strcpy a string to the other fields of the struct, it works fine.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct {
char *datafile;
char *logfile;
char mode;
} general_settings;
void setSettingsData(void){
log_trace("parsing config file for general settings initialisation");
config_error_t rc = config_parse("config.ini", handle_settings_ini_file);
if (rc != CONFIG_ERROR_NONE) {
log_error("Error parsing configuration: %s on line %lu", config_get_error_string(rc), config_get_line_number());
} else {
log_info("Settings parsed successfully!");
}
}
static config_error_t handle_settings_ini_file(char *section, char *key, char *value) {
if(section != NULL && !strcmp("Allgemein", section)) {
if (!strcmp("mode", key)) {
general_settings.mode = strdup(value); // ??????
log_info("Program Execution mode set to %s", value);
} else {
log_fatal("Unrecognized setting. Check for typos. Exiting...");
exit(0);
}
}
return CONFIG_ERROR_NONE;
}
Since value is a char *, you can get the char it points to with *value.
So you want general_settings.mode = *value;.
You could also use general_settings.mode = value[0];
Since a[b] is the same as *(a+b), *(value + 0) is the same as value[0] and also the same as *value.
I am new to C language somehow and I am trying here to call a function "func" in main function but it gives me compiling error. I tried to search for examples similar to this situation in Google but stil getting errors.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
struct str {
int value;
uint32_t ptr_next;
};
void func(int arg, char* arr[]);
int main() {
int Arg;
char* Arr[1];
func(Arg, *Arr[1]);
return 0;
}
void func(int arg, char* arr[]) {
int list;
struct str r;
FILE* file = fopen(arr[1], "rb");
do {
list = fread(&r, sizeof(struct str), 1, file);
if (list > 0)
printf("%d ", r.value);
fseek(file, r.ptr_next, 0);
}
while ((r.ptr_next != 0) && (list > 0));
}
The question is how can I call functions by value in C language?
C only supports calling functions by value, calling by reference was added in C++ and uses the & symbol.
The value you are passing to the function is a location in memory, a pointer. If you want to hand to the function a copy of the data at that memory location you'll need to make a copy for it.
// Assuming that Arg and Arr are initialized.
char* Arr2[]; // Make a storage place for the char**.
Arr2 = malloc(Arg*sizeof(char*)); // Make the right number of char*s in it
for(int e=0; e<Arg; e++) { // For each elem in the main array:
Arr2[e]=malloc(sizeof(char)*strlen(Arr[e])); // Make space for the chars,
strcpy(Arr2[e],Arr[e]); // And copy them.
}
Side note
You haven't initialized Arg or Arr in main. I suspect that you might have meant the command line parameters.
int main(int Arg, char* Arr[])
I have a struct of pointers and a global pointer to use in functions declared after main. Now declaring the functions with those same name of pointers is fine. But when I call it within another function (because its like a menu type program), I kept getting different types of errors.. Like expression is needed, unexpected type, etc. My question is simply how to I call the parameters for the function to work. I haven't used C in years so the solution might seem simpler than it sounds like. The code below will show you what I mean.
StudentPtr studentArray
StudentPtr** studentArray
struct StudentPtr *studentArray
*StudentPtr studentArray[]
(Pretty much moving the pointers around and using struct as prefix)
typedef struct Student {
char *firstName;
char *lastName;
char *id;
char *email;
} Student, *StudentPtr;
//Prototypes:
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);
int displayData(StudentPtr studentArray, int n);
int displayDataAll(StudentPtr studentArray);
int main()
{
return 0;
}
int command(char line[])
{
//other code here
//some more code..
//......
//error below
if(lineSize==0) /* If the command is empty, asks again for a command */
{
return 0;
}
else
{
if(strncmp(line,"1",lineSize)==0)
{reset();}
else if(strncmp(line,"2",lineSize)==0)
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
else if (strncmp(line,"3",lineSize)==0)
{modify(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //here as well
else if(strncmp(line,"4",lineSize)==0)
{displayDataAll(StudentPtr studentArray);} //here too
else if(strncmp(line,"5",lineSize)==0)
{return 1;}
else
{noComm();}
}
return 0;
}
//example of the functions supposed to be used
int fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n)
{
//get the start of the nth record
//Ptr arithmetic
StudentPtr currentStudentptr = studentArray+(n-1);
//allocate memory for the character pointers
currentStudentptr->firstName =malloc(sizeof(char)*20);
strcpy(currentStudentptr->firstName,f);
//... same for others
return 0;
}
The calling of the function here should properly call the functions that are further down.
You are mixing syntax for function declaration and definition with syntax for calling a function:
{fillData(StudentPtr studentArray,char* f, char* l, char* id, char* e,int n);} //the first parameter here
In a function call you mustn't specify the type. You only provide the arguments:
{fillData(studentArray, f, l, id, e, n);}
You do not show any variable definiton. Therefore I cannot tell if the variables have correct types or if you need to add some & operators here and there...
That is the reason why a minimum complete verifyable example is mandatory.
So I was having some fun with c when I tried this:
#include <stdio.h>
#include <string.h>
typedef void (*Function)(char *);
void helloWorld(char *);
void execute(Function, char *);
Function func;
int main(void){
char *message = "StackOverflow";
execute(helloWorld, message);
printf("%s", message);
return 0;
}
void helloWorld(char *message){
printf("HelloWorld, %s.\n", message);
message = "DONE";
printf("[%s]\n", message);
}
void execute(Function function, char * msg){
func = function;
func(msg);
}
Apparently I am not able to use pointers - which I used as parameter - as return value of pointer functions.
Well, can someone explain this behavior? How can I get return value(s) of void function?
So I found a solution while writing the question.
Apparently char pointers are not actually pointers, somehow. When I realised this it tried using pointer to pointer (**) instead and it worked.
#include <stdio.h>
#include <string.h>
typedef void (*Function)(char **);
void helloWorld(char **);
void execute(Function, char **);
Function func;
int main(void){
char *message = "StackOverflow";
execute(helloWorld, &message);
printf("%s\n", message);
return 0;
}
void helloWorld(char **message){
printf("HelloWorld, %s.\n", *message);
*message = "DONE";
printf("[%s]\n", *message);
}
void execute(Function function, char ** msg){
func = function;
func(msg);
}
In your original code:
void helloWorld(char *message){
printf("HelloWorld, %s.\n", message);
message = "DONE";
printf("[%s]\n", message);
}
the line message = "DONE"; will change the local (or "automatic") variable named message, because function parameters are, for all intents and purposes, local variables in C.
Thus, the value of the message local variable from main will not change, as those are two different variables.
Now, in your second example, you are passing pointers to pointers:
void helloWorld(char **message){
printf("HelloWorld, %s.\n", *message);
*message = "DONE";
printf("[%s]\n", *message);
}
So, your *message = "DONE"; is now changing what the message (parameter) points to, and it is pointing to the message from main(), thus it is changing message from main(). The message from helloWorld() itself is not changed here.
Of course, there is nothing special about character pointers w.r.t other pointers, they are pointers as much as any other. The only special thing is treating string literals as character pointers, but that doesn't matter here.
I'm using the ffcall (specifically the avcall package of ffcall) library to dynamically push parameters to variadic functions. i.e. we have
int blah (char *a, int b, double c, ...);
and we want to call this function with values taken from the user. To do this, we create an avcall version of the function:
int av_blah (char *a, int b, double c, char **values, int num_of_values)
{
av_alist alist;
int i, ret;
av_start_int (alist, &blah, &ret); //let it know which function
av_ptr (alist, char*, a); // push values onto stack starting from left
av_int (alist, b);
av_double (alist, c);
for (i=0;i<num_of_values;i++)
{
// do what you want with values and add to stack
}
av_call (alist); //call blah()
return (ret);
}
Now, the function I am using avcall with is:
int read_row (struct some_struct *a, struct another_struct *b[], ...);
And it is used like so:
struct some_struct a;
struct another_struct **b = fill_with_stuff ();
char name[64];
int num;
while (read_row (&a, b, name, &num)==0)
{
printf ("name=%s, num=%d\n", name, num);
}
But I want to use avcall to capture a certain amount of values from this function and I do not know this information in advance. So I thought I'd just create an array of void pointers and then malloc space according to the type:
char printf_string[64]=""; //need to build printf string inside av_read_row()
void **vals = Calloc (n+1, sizeof (void*)); //wrapper
while (av_read_row (&a, b, vals, n, printf_string) == 0)
{
// vals should now hold the values i want
av_printf (printf_string, vals, n); //get nonsense output from this
// free the mallocs which each vals[i] is pointing to
void **ptrs = vals;
while (*ptrs) {
free (*ptrs); //seg faults on first free() ?
*ptrs=NULL;
ptrs++;
}
//reset printf_string
printf_string[0]='\0';
printf ("\n");
}
And av_read_row is just:
int av_read_row (struct some_struct *a, struct another_struct *b[], void **vals, int num_of_args, char *printf_string)
{
int i, ret;
av_alist alist;
av_start_int (alist, &read_row, &ret);
av_ptr (alist, struct some_struct *, a);
av_ptr (alist, struct another_struct **, b);
for (i=0;i<num_of_args;i++)
{
switch (type) //for simplicity
{
case INT: {
vals[i] = Malloc (sizeof (int));
av_ptr (alist, int*, vals[i]);
strcat (printf_string, "%d, ");
break;
}
case FLOAT: {
//Same thing
}
//etc
}
}
av_call (alist);
return (ret);
}
I have been experiencing a bunch of memory corruption errors and it seems as though it doesn't like what I'm doing here. I can't spot anything wrong with the way I did this, can you? At the moment, it doesn't like it when I try to free the mallocs inside the av_read_row while loop. Can anyone see what I'm doing wrong, if anything?
Thanks
The only information I can easily find about avcall is from 2001, but it does suggest POSIX. If you can run your stuff on Linux, valgrind will find your memory faults in a jiffy. It's a terrific tool.
I did not go into the finer details of the code, but can say the following
Using stack for passing large number of arguments is not advisable, as stack is limited. I am not sure if av_stuff really checks the stack limit.
Isn't there a simpler method to do the same operation instead of pushing the variable to stack?