I'm trying to pass some variadic parameters through pointer but I haven't quite get it.
The parser isn't working, but this is not my problem.
I'm using a subset of C, but don't worry about syntax or lexic.
It is supposed to be used like:
void functionX(void){
action[100]="GO_PLAY(12345,23)";
char id[10];
char offset[10];
ParseCommand("GO_PLAY",action,2,&id,&offset);
// after this id should be "12345" and offset should be "23"
}
bool ParseCommand(char *command, char * buffer,int count, ...){
bool returnvalue=FALSE;
int command_len=O_strlen(command);
int buffer_len=O_strlen(buffer);
int j=command_len+1;
va_list ap;
int parameter=0;
char *parsed_text;
va_start(ap, count); /* Initialize the argument list. */
while(parameter<count) {
while(buffer[j]!=','&& buffer[j]!=')') //search argument
j++;
if(j<buffer_len) { // argument found
calloc(MODULE,parsed_text,j-(command_len+1),sizeof(char));
substr(command_len+1,j,buffer,parsed_text,buffer_len);
*va_arg(ap,char*)=parsed_text; // why isnt this working?
parameter++;
j++; // to continue to search
}
}
leave:
va_end (ap);
return returnvalue;
}
Instead of *va_arg(ap,char*)=parsed_text,
try : sprintf(va_arg(ap, char*), "%s", parsed_text);
va_arg(ap,char*) returns a value of type char*. That is, it's a pointer to char. But you're trying to store a char* value at the place it points to. I think you actually want to copy the characters you've extracted from the command there, with strcpy or memcpy or something of the kind.
Incidentally, if you do that then your parser -- just like the scanf functions if used incautiously -- will be vulnerable to buffer overflows if it's asked to parse something containing arguments that are too long for the variable they're being stored in. But that's a separate issue, and it may or may not be a serious problem depending on the rest of your code.
(Perhaps instead you were intending to copy the (pointer) value of parsed_text rather than copying the characters. But then you have another problem: id and offset aren't pointer variables so you couldn't do that even if you wanted to.)
Other issues:
I don't see any memory being allocated for parsed_text, but it's hard to tell without seeing the definition of substr. Is it a function or a macro? What exactly is it supposed to do? Actually, if substr is allocating memory, you have a different problem, because nothing is freeing it again.
If your input command has the wrong syntax, your while loop can run off the end of the string, looping for ever until it tries to access some memory it's not allowed to. This will happen, e.g., if you call ParseCommand("GO_PLAY","GO_PLAY(broken",2,&id,&offset).
Related
I have been working with C for the first time in a long time and one of the biggest problems for me has been working with strings, since they aren't expressed as well as they are in Python.
From what I know and understand, a char * is just a pointer to a string(or rather, the first character in a string). A char[] is very similar and can be used the same way.
My first question is a little side question, but while we use it to execute the same things, is there a difference in correctness or how the compiler views it?
Going ahead, I know that char *[] is just an array, but each element is a pointer of type char *. So through that each element when deferenced/accessed would just return a string. Which is why char *argv[] just takes values from command line.
For a problem that I was working on I needed a a 2D array of strings and had been trying to run it is char *[][] and making function calls for it.
I have a function type defined as void runoff_function(candidates *, int a, int b,char * array[a][b]); That expects a 2D array of character pointers.
My main function has a variable defined and populated as char* list[n][argc];
Except when running a loop to initialize user inputs:
char* list[n][argc];
for(int i=0;i<n;i++)
{
printf("Voter %d\n",(i+1));
for(int j=1;j<argc;j++)
{
printf("Rank %d\t",j);
scanf("%s",list[i][j-1]);
}
I get a seg fault after my first input and I don't know why.
The declaration char* list[n][argc]; reserves space for the string pointers, only. However, each string needs a place to store its characters. You must supply this space.
The easiest and safest way to do it, is to instruct scanf() to allocate some space on the heap for your string. This is done by adding the "m" modifier to the "%s" conversion. scanf() will then expect a char** as the argument, and store the pointer to a new string at that location. Your code would look like this:
scanf("%ms", &list[i][j-1]);
Note that it is your job to subsequently get rid of the memory allocations. So, once you are done with your strings, you will need to add a loop that calls free() on each cell of the 2D array:
for(int i=0;i<n;i++) {
for(int j=1;j<argc;j++) {
free(list[i][j-1]);
}
}
The "%ms" format is specified by the POSIX.1-2008 standard, so safe to use on any modern linux.
Im trying to implement a function with the following prototype.
int get_next_line(const int fd, char **line) .
The first parameter is the file descriptor that will be used to read.
The second parameter is the address of a pointer to a character that will be used
to save the line read from the file descriptor.
The only thing i know about difference of passing reference and value is that referencing allows you modify the content value.
But for the given prototype, we have the address of the first characters, so i don't fully understand the need for the double pointer.
[Edited] : We store one line of chars inside '**line'.
My question is:
Why use **line and not just *line , or why not ?
int get_next_line(int fd, char **line);
This is a usable function. It presumably allocates a character array of tentatively sufficient size, reads a line into it, reallocates and reads the remainder if necessary, and then passes the allocated string back by assigning it to the dereferenced second argument (*line = allocated_string;).
int get_next_line(int fd, char *line);
This is patent nonsense. There is no way to write get_next_line that is remotely as usable as the previous one. It cannot determine the size of the character array passed to it, nor can it reallocate this array. The only way to specify this function to behave somewhat sensibly is to demand that the argument must be an array of some pre-determined size specified elsewhere. This could only be useful in some pretty narrow contexts.
Note that this is not an immediately obvious observation. The C language used to have gets up until 2011. Programmers used to be rather careless back when.
int get_next_line(int fd, char *line, size_t size);
This could be a somewhat useful function. It could work almost like the standard read function, except it wouldn't read past the first end-of-line character. (Or like fgets for Posix fike handles.) Of course users need to deal with the case of the input line being longer than their array. Presumably get_next_line would return the number if scanned characters.
Note const int is useless in function prototypes. All standard functions specify int in such cases.
I have a function named testdynamic which is called dynamically with dlopen and dlsym. Now, I have created a structure:
typedef struct BigStruct{
char el[2000];
}BigStruct;
which is used to store the parameters for the function. Then, I allocate space to a variable named:
void *cur = (void*)malloc(totalSize);
where, totalSize is the size of the parameters. I have this information beforehand.
After that I copy all the parameters to cur.
Then, I cast it to BigStruct like this:
BigStruct *bg;
bg = (BigStruct*)cur;
And run it like this:
void* ch = (void*)testdynamic(*bg);
Now in the function testdynamic when I am printing the parameters, I am getting correct values for all data types like char**, int*, int, etc.
The only data type which is not working is char*. Even before calling the function with *bg, the contents of bg->el is correct even for char*. But, after calling, an error occurs.
What could be the problem?
Here is the code of testdynamic
char* testdynamic(char* x, char* y){
printf("%s %s\n", x, y);
return "hello";
}
I want to pass the parameters to the function testdynamic from my code.
This testdynamic can be any function which could accept any parameter of any type.
I get the information about the function during runtime. Since the size of char* is 1, I am casting everything to char* and then passing it to the function.
At this point, I am getting a runtime error if I am printing anything inside testdynamic which is of type char*.
You are assuming that BigStruct looks exactly like an array of 2000 characters. This is compiler dependent and unlikely to be true. I guess you really want to copy the data pointed to by cur into the el array and not to write it all over BigStruct itself which will have some internal storage format that you cannot know.
If totalSize > sizeof(BigStruct), you have problems for you are not passing a complete copy of your data to testdynamic(), likely messing up the copy and hence undefined behavior.
If totalSize < sizeof(BigStruct), you have problems for you are reading memory space you do not own when you pass *bg to testdynamic() - hence undefined behavior.
You are much safer simply with
bg = malloc(*bg);
There other questionable program issues going on here too, but a more complete posting would be needed.
After reading it some more....
you're passing in one parameter for a function that requires 2 parameters.
Are you using -Wall for warning treated as errors during compilation? The second parameter isn't passed in, i.e, argument y is null. Accessing null would cause the problem.
So to summarise what I understand you're doing:
Treating cur as a char* and copying a parameter list into it
Casting cur as a BigStruct* and then passing it to the testdynamic function.
This seems to me like an odd way of going about this, and without looking inside the testdynamic function I would guess that this is what is causing the error. I would recommend changing your definition of BigStruct:
typedef struct {
char * el;
} BigStruct;
And that way, you can malloc space for your char array, copy your parameter list to it, and then set the char * in the BigStruct to point to the relevant block of memory as follows:
char * cur = malloc(totalSize);
// Copy parameters over into cur
BigStruct * bg = malloc(sizeof(BigStruct));
bg->el = cur;
And then call your testdynamic function again. Try this, do you still get a runtime error?
edit: having seen the content of the testdynamic function, I can see several problems with it
char* testdynamic(char* x, char* y){
printf("%s %s\n", x, y);
return "hello";
}
The function accepts 2 char * but you only seem to pass 1 in your code. What should it print for y if you only give it an argument for x?
Let's assume you are now passing arguments for both x and y. Are you sure that both strings are null-terminated? printf works by printing characters until it finds the '\0' character.
You can't just return a string literal from within a function like that. That string literal belongs to the function, and once the function returns you can't guarantee that the memory which held the string will still be safe to access again. If you want to return a string like that, you should first malloc() space for the string and return the address to the allocated block of memory.
To provide accurate, non-opinionated comments, a copy of the code is required. Thus, I have taken your comments and produced the following code. It is probably NOT what you want to do. However, a programming problem should be approached in steps or increments.
That is, get something simple to work and then make it a little more complex, but still working, and work towards your final version. This is how many of us work. No one is able to write a complex program correctly the first time, especially if new to the language!
#include <stdio.h>
#include <stdlib.h>
char *testdynamic(char *x, char* y){
printf("%s %s\n", x, y);
return "hello";
}
main()
{
typedef struct BigStruct{
char el[2000];
} BigStruct;
char *ret_char_ptr;
BigStruct *bg;
char x[] = "abcd";
char y[] = "23456";
bg = malloc(sizeof(BigStruct));
// invoke the testdynamic function
ret_char_ptr = testdynamic(x, y);
printf("%s\n", ret_char_ptr);
}
I ran this code on Eclipse/Microsoft C compiler and got the following output:
abcd 23456
hello
Note. BigStruct has yet to used in this code. Not sure what your intent is, but C does provide a way to pass parameter lists that vary in length and data from several different calls to the same function.
This only works if the size is sizeof(BigStruct)
You can't assume a structure is the size of its content, since compilers might make assumptions of alignment, etc.
If you just want 20,000 chars, then malloc it inside the BigStruct like others have suggested.
i am trying to write an easier version of scanf. i want to basically be able for a pointer to be assigned whatever was scanned on user input like this:
int *p = (int) w_insc();
so here is my implementation:
void *w_insc()
{
void *temp = 0;
scanf("???", &temp);
return &temp;
}
i am confused as what to assign the format parameter in scanf to. i also think returning an address of a variable that will soon be destroyed is not right so i thought of doing this:
int *p = 0;
p = (int) w_insc((int) p);
can someone help
You are right that returning a pointer to a soon-to-be-destroyed variable is not correct. You can solve this problem by returning a pointer to a memory region allocated with malloc (although the caller must remember to free this memory), or by taking a pointer as the argument to w_insc, and then filling in the pointer with the returned value.
However, there are much broader issues with trying to implement the w_insc function. There is no way for w_insc to know what the caller expects. Just because the caller casts the return value of w_insc to int doesn't allow w_insc to know that it should return an int. The only information that a C function has available to it is its set of parameters, plus any global variables in the program (and global variables are usually the wrong way to solve your problem). Note that a C function has no way of knowing what the caller will do with its return value. As a result, there is no way to write w_insc to take no parameters and return something scanned correctly based on some cast that the caller makes.
You could add a parameter to w_insc, making the declaration into
int w_insc(const char *format, ...)
This allows the caller to pass in a format string and a series of arguments detailing what they expect to get out of standard input. However, with this implementation you have just wrapped scanf with ... another function that looks just like scanf.
My advice: use the standard library functions, since they are standardized, and someone reading your code will know instantly what it means, rather than having to read through the definition of a nearly-trivial wrapper like the w_insc you have described.
I'm trying to write a simple C program on Ubuntu using Eclipse CDT (yes, I'm more comfortable with an IDE and I'm used to Eclipse from Java development), and I'm stuck with something weird. On one part of my code, I initialize a char array in a function, and it is by default pointing to the same location with one of the inputs, which has nothing to do with that char array. Here is my code:
char* subdir(const char input[], const char dir[]){
[*] int totallen = strlen(input) + strlen(dir) + 2;
char retval[totallen];
strcpy(retval, input);
strcat(retval, dir);
...}
Ok at the part I've marked with [*], there is a checkpoint. Even at that breakpoint, when I check y locals, I see that retval is pointing to the same address with my argument input. It not even possible as input comes from another function and retval is created in this function. Is is me being unexperienced with C and missing something, or is there a bug somewhere with the C compiler?
It seems so obvious to me that they should't point to the same (and a valid, of course, they aren't NULL) location. When the code goes on, it literally messes up everything; I get random characters and shapes in console and the program crashes.
I don't think it makes sense to check the address of retval BEFORE it appears, it being a VLA and all (by definition the compiler and the debugger don't know much about it, it's generated at runtime on the stack).
Try checking its address after its point of definition.
EDIT
I just read the "I get random characters and shapes in console". It's obvious now that you are returning the VLA and expecting things to work.
A VLA is only valid inside the block where it was defined. Using it outside is undefined behavior and thus very dangerous. Even if the size were constant, it still wouldn't be valid to return it from the function. In this case you most definitely want to malloc the memory.
What cnicutar said.
I hate people who do this, so I hate me ... but ... Arrays of non-const size are a C99 extension and not supported by C++. Of course GCC has extensions to make it happen.
Under the covers you are essentially doing an _alloca, so your odds of blowing out the stack are proportional to who has access to abuse the function.
Finally, I hope it doesn't actually get returned, because that would be returning a pointer to a stack allocated array, which would be your real problem since that array is gone as of the point of return.
In C++ you would typically use a string class.
In C you would either pass a pointer and length in as parameters, or a pointer to a pointer (or return a pointer) and specify the calls should call free() on it when done. These solutions all suck because they are error prone to leaks or truncation or overflow. :/
Well, your fundamental problem is that you are returning a pointer to the stack allocated VLA. You can't do that. Pointers to local variables are only valid inside the scope of the function that declares them. Your code results in Undefined Behaviour.
At least I am assuming that somewhere in the ..... in the real code is the line return retval.
You'll need to use heap allocation, or pass a suitably sized buffer to the function.
As well as that, you only need +1 rather than +2 in the length calculation - there is only one null-terminator.
Try changing retval to a character pointer and allocating your buffer using malloc().
Pass the two string arguments as, char * or const char *
Rather than returning char *, you should just pass another parameter with a string pointer that you already malloc'd space for.
Return bool or int describing what happened in the function, and use the parameter you passed to store the result.
Lastly don't forget to free the memory since you're having to malloc space for the string on the heap...
//retstr is not a const like the other two
bool subdir(const char *input, const char *dir,char *retstr){
strcpy(retstr, input);
strcat(retstr, dir);
return 1;
}
int main()
{
char h[]="Hello ";
char w[]="World!";
char *greet=(char*)malloc(strlen(h)+strlen(w)+1); //Size of the result plus room for the terminator!
subdir(h,w,greet);
printf("%s",greet);
return 1;
}
This will print: "Hello World!" added together by your function.
Also when you're creating a string on the fly you must malloc. The compiler doesn't know how long the two other strings are going to be, thus using char greet[totallen]; shouldn't work.