I'm experimenting with using dynamic libraries and C on Linux. The following code will print wrong ouput:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *ver = dlsym(dl, "show_version");
printf("%s\n", ver);
}
If I make the following change the output will be correct:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *(*ver)() = dlsym(dl, "show_version");
printf("%s\n", ver());
}
I'm not sure what char *(*ver)() is doing and why it's needed? Can anyone explain?
dlsym(dl, "show_version") returns the address for the symbol show_version. Since show_version is a function, that is the address of the function.
char *ver = dlsym(…); puts that pointer in a char *, which is basically useless. The pointer to a function does not point to bytes that are useful to print. Then printf("%s\n", ver); says to print the bytes that ver points to as if they were a string. But the bytes there are (in a typical C implementation) machine code for the function. They are not the bytes of a character string you want to print.
char *(*ver)() = dlsym(…); defines ver to be a pointer to a function whose arguments are not specified and that returns a char *. To see this:
char something declares something to be a char.
char *something declares something to be a pointer to a char.
char *something() declares something to be a function whose arguments are not specified that returns a pointer to char.
char *(*something)() declares something to a pointer to such a function.
Then, in printf("%s\n", ver());, ver() calls this function. The char * it returns is passed to printf to be printed.
dlsym - obtain address of a symbol in a shared object or executable
This means that when you do dlsym(dl, "show_version"); you are not actually calling the function show_version in your shared library. You obtain the address of that function - which can be used to call the function over and over again.
To "decode" what char *(*ver)() means, you can use what is often called the Clockwise/Spiral Rule
+-----+
| V
char* (*ver) () ver is a
^ ^ | | pointer to
| | | | a function (taking no arguments)
| +-+ | returning char*
| |
+------------+
I assume the above matches the signature of the show_version function that you put in the shared library. Example:
// a function (taking no arguments), returning a char*
char *show_version(void) {
static char version[] = "1.0";
return version;
}
Using the same rule on your first attempt, char* ver:
char* ver
^ | ver is a
| | char*
+----+
You need a pointer to a function (with the correct signature) to be able to call the function and get the result you want. You can't call a char* and when you do printf("%s\n", ver); it'll just start reading the memory at the address (where your function is stored) until it finds a null terminator. You probably see just gibberish.
If you on the other hand have a proper function pointer, you can as you've noticed, call the function it points at with ver() and you get a char* in return which points at the string your dynamically loaded function returned.
You can also use function pointers in your programs without involving shared libraries.
#include <stdio.h>
long foo(short x, int y) {
return x + y;
}
int main() {
long(*foo_ptr)(short, int) = foo;
// foo_ptr is a pointer to a function taking (short, int) as
// arguments and returning a long
printf("%ld\n", foo(1, 2) ); // prints 3
printf("%ld\n", foo_ptr(1, 2) ); // also prints 3
}
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
char *preorden="GEAIBMCLDFKJH";//line 5
error in the above line
char *inorden="IABEGLDCFMKHJ";//line 6
error in this line
char *postorden;
error in this line
void post(char *pre, char *in, char *pos,int n)
{
int longIzqda;
if(n!=0){
pos[n-1]=pre[0];
longIzqda=strchr(in,pre[0])-in;
post (pre+1,in,pos,longIzqda);
post (pre+1+longIzqda,in+1+longIzqda,pos+longIzqda,n-1-longIzqda);
}
}
int main(int argc,char *argv[])
{
int aux;
aux=strlen(preorden);//convert to string
postorden=(char *)malloc(aux*sizeof(char));//use of malloc function
if (postorden){
printf("The preorden is: %s\n",preorden);
printf("The inorden is: %s\n",inorden);
post(preorden,inorden,postorden,aux);
postorden[aux]='\0';
printf("The postorden calculated is: %s\n",postorden);
free(postorden);
}
else{
fprintf(stderr,"Whithout memory\n");
return 1; // return 1
}
return 0;
}
the error is in the line 5 and 6
the compiler says:
deprecated conversion from string constant to 'char*' [-Wwrite-strings]
There are few issues with your code, firstly this
char *preorden="GEAIBMCLDFKJH";//line 5
forces compiler to warn you like below if compiled with -Wwrite-strings flags in C
deprecated conversion from string constant to 'char*'
[-Wwrite-strings]
because the string literal GEAIBMCLDFKJH stored in read only section of primary memory i.e pointer where it points, that contents is read only, hence instead of char* use const char*. for e.g
char *preorden = "GEAIBMCLDFKJH";/* preorden is normal pointer but "GEAIBMCLDFKJH" is read only, hence error */
And
const char *preorden = "GEAIBMCLDFKJH"; /* const char *ptr means ptr contents is read only */
Secondly, here
postorden=(char *)malloc(aux*sizeof(char));//use of malloc function
casting of malloc result is not required as malloc() return type is void* which is automatically and safely promoted to any other pointer type, Read Do I cast the result of malloc?. for e.g
postorden = malloc(aux * sizeof(*postorden));//use of malloc function
Also here(this point is about wrong comment on below line, please don't mind)
aux=strlen(preorden);//convert to string
strlen(preorden) returns the length of string pointed by preorden and gets assigned to aux not as written in comments(convert to string).
And change the post() definition to
void post(const char *pre, const char *in, char *pos,int n) {
/* some code*/
}
The message “deprecated conversion from string constant to 'char*' [-Wwrite-strings]” arises because the code was compiled as C++ code, which has different rules about string literals and pointer conversions from C.
This can be fixed by compiling the code as C code or worked around by inserting an explicit cast to char *.
I'm trying to assign data type to world but unable to figure it out.
#include <stdarg.h>
#include <stdio.h>
#define TRACE(arg) TraceDebug arg ;\
void TraceDebug(const char* format, ...);
void TraceDebug(const char* format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
int main(void)
{
int a =55;
TRACE((Hello,a));
return 0;
}
Below is the error statement in detail.
main.c: In function 'main':
main.c:28:12: error: 'Hello' undeclared (first use in this function)
TRACE((Hello,a));
^
main.c:13:32: note: in definition of macro 'TRACE'
#define TRACE(arg) TraceDebug arg ;\
^
main.c:28:12: note: each undeclared identifier is reported only once for each function it appears in
TRACE((Hello,a));
^
main.c:13:32: note: in definition of macro 'TRACE'
#define TRACE(arg) TraceDebug arg ;\
^
Is there anyway possible to declare Hello as a variable, after declaring I need to get the address of the variable.
In simple I want to change the below code into a variadic function arguments
for example #define QU(arg1,arg2) as #define QU(arg1,...) since variadic macro is not supported am using variadic functions.
#define TRACE(arg1) QU arg1
#define QU(arg1,arg2) {static const char arg1; \
printf("%p\n",(void*)&arg1);\
printf("%d\n",arg2);}\
int main(void)
{
int aaa =333;
int bbb =444;
TRACE((Hello,aaa));
TRACE((Hello2,bbb));
return 0;
}
1) (title) How to declare the data type for variable arguments?
2) (1st question) I'm trying to assign data type to world but unable to figure it out.
1) The data type for the variadic argument (represented by the ellipses: ... ) is always the type of the variable preceding the ellipses . For this prototype:
int variadicFunc(int a, const char *b, ...);
^^^^^^^^^^ ^^^
type assumes the type const char *
2) From content of your question only, the answer could be to be use a typedef statement:
typedef char World; // a new type 'World' is created
But there are clarifications in the comments:
if i change the string to variable i can reduce the memory size,... (you)
You want to have a variable argument list to pass variables existing in your program that you want to place on a Trace list for debugging
purposes. (is that close?)... (me)
(is that close?) yes, that's the thing am trying to do... Are you always going to pass the same type to this function? Ahh, type will
be like TRACE(("Hello", a,"world")); (you)
It appears you want to enter a variable number of either string literals, or string variables as function arguments, then for those items to be placed into variables, then the addresses of those variables to be stored in a file, for the purpose of saving space.
The following code illustrates how you can pass a variable number of strings (in different forms) into a function, and have the address and content retained into a struct. From this, you should be able to adapt from what I have done here, to something more useful to your needs. Note, I have reserved the first string argument to be used a file location to store addresses.
#define MAX_LEN 200
typedef struct {
unsigned int addr;
char str[MAX_LEN];
} DATA;
int variadicFunc(int argCount, const char *str, ...);
int main(void)
{
char a[] = {"this is a string"};
char b[] = {"another string"};
char c[] = {"yet another string"};
// count non-variable v1 v2 v3 v4
variadicFunc(4, ".\\storage.txt", a, b, "var string", c);
// ^count of variable argument list
return 0;
}
int variadicFunc(int argCount, const char *str, ...)
{
va_list arg;
int i;
char sAddr[10];
DATA *d = calloc(argCount, sizeof(*d));
va_start(arg, str);
FILE *fp = fopen(str, "w");//using first string as filename to populate
if(fp)
{
for(i=0;i<argCount;i++)
{
// retain addresses and content for each string
strcpy(d[i].str, va_arg(arg, const char *));
d[i].addr = (unsigned int)&d[i].str[i];
sprintf(sAddr, "%X\n", d[i].addr);
fputs(sAddr, fp);
}
fclose(fp);
}
return 0;
}
Consider the following code:
#include <stdio.h>
void f(const char * str) {
str = "java";
}
void main (int argc, char * argv[]) {
const char *str = "erlang";
f(str);
printf("%s\n", str);
}
The output is "erlang" and I don't quite know why..
My current knowledge says that string literals "erlang" and "java" are both stored in the process adress space, within section "constants". And according to this, the fucntion f should change the pointer to point to "java", but this doesn't happen. Could someone please explain what is going on here?
Because function arguments are passed by value in C and modifying arguments in callee won't affece caller's local variables.
Use pointers to modify caller's local variables.
#include <stdio.h>
void f(const char ** str) { /* add * to declare pointer */
*str = "java"; /* add * to access what is pointed */
}
int main (int argc, char * argv[]) { /* use standard signature */
const char *str = "erlang";
f(&str); /* add & to get a pointer pointing at str */
printf("%s\n", str);
}
C has copy by value. When str is passed as an argument to f, it is copied first, and that very copy is actually passed to f. Assigning "java" to that copy doesn't do anything to the original str in main.
Since you are passing the value that means call by value you will see the output as java if you pass the reference like this:
#include <stdio.h>
void f(const char ** str) {
*str = "java";
}
void main (int argc, char * argv[]) {
const char *str = "erlang";
f(&str);
printf("%s\n", str);
}
output:
rabi#rabi-VirtualBox:~/rabi/c$ gcc ptr1.c
rabi#rabi-VirtualBox:~/rabi/c$ ./a.out
java
Function parameters are its local variables. You can imagine the function definition and its call the following way (I changed the name of the parameter from str to s for clearity)
void f(/*const char * s*/) {
const char *s = str;
s = "java";
}
//...
const char *str = "erlang";
f(str);
Any changes of the local variable s does not influence on the original variable str used as the argument. The variable str itself was unchanged.
You should pass arguments by reference if you are going to change them in a function. For example
#include <stdio.h>
void f( const char ** str )
{
*str = "java";
}
int main( void )
{
const char *str = "erlang";
f( &str );
printf( "%s\n", str );
}
The program output is
java
Take into account that according to the C Standard function main shall have return type int.
Could someone please explain what is going on here?
Many good answers all ready yet thought I'd try to perform a detailed walk-though with OP with slightly modified code.
Consider what happens with f("Hello World"). "Hello World" is a string literal. It initializes a char array. When an array is passed to a function or assigned to a pointer, it is converted to the address of the first element of the array. f() receives a copy of the address of 'H' in its str. #1 prints "Hello World". str is re-assigned to the address of 'j'. #2 prints "java". The function ends without affecting "Hello World".
With str = "erlang", str receives the address of the 'e'. #3 prints "erlang". On the function call, the value of main()'s str is copied to the f()'s str. #1 prints "erlang". Like before, str is re-assigned to the address of 'j'. #2 prints "java". The function ends without affecting main()'s str. #4 prints "erlang".
#include <stdio.h>
void f(const char * str) {
printf("f() before str='%s'\n", str); // #1
str = "java";
printf("f() after str='%s'\n", str); // #2
}
int main(void) {
f("Hello World");
puts("");
const char *str = "erlang";
printf("main() before str='%s'\n", str); // #3
f(str);
printf("main() after str='%s'\n", str); // #4
return 0;
}
Output
f() before str='Hello World'
f() after str='java'
main() before str='erlang'
f() before str='erlang'
f() after str='java'
main() after str='erlang'
As to OP's question:
C literals, where are these stored?
The location of a string literal is not defined in C. It might use the "process address space, within section constants", it might not. What is important is that an array is formed and the address of the first character is given in assignment to a const char *. Further detail: writing to this address is undefined behavior (UB), it may "work", fail, seg-fault, etc.
This would be more obvious if you changed the name of the argument for f...
#include <stdio.h>
void f(const char * foo) {
foo = "java";
}
int main (int argc, char * argv[]) {
const char *str = "erlang";
f(str);
printf("%s\n", str);
}
foo is a different variable to str. It has a different name, a different scope, and can contain a different value. The changes to foo won't propagate to str. If you wanted to modify str from within f, you would need to make f look like this:
void f(const char **foo) {
*foo = "java";
}
... and pass a pointer to str to f like so: f(&str);.
Did you happen to notice how I changed void main to int main? There are only two signatures for main entry points (excluding the equivalents) that are guaranteed by the standard to be portable:
int main(void) { /* ... */ }
... and ...
int main(int argc, char *argv[]) { /* ... */ }
Either way, main always returns int (or equivalent). This shouldn't inconvenience you too much, as in C99 (any half-decent compiler that's newer than fifteen years old) and C11 there's this little gem which allows you to omit return 0; from main:
If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;11) reaching the } that terminates the main function returns a value of 0.
So if anything, your code using an int main entry point is not just portable but also one byte shorter than your code using a non-portable void main entry point.
I want to write a program which will verify whether the string is palindrome or not.
But there is an error when I try to pass strings[0] to removeSpaces function which will remove spaces.
Why does 'comflicting types error' occurs? What is wrong?
The whole code of programm:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * removeSpaces(char *); // prototype
int main()
{
char *strings[2]; // created array of pointers
strings[0] = strdup("a man a plan a canal panama");
printf("%s\n", strings[0]);
strings[1] = removeSpaces(strings[0]);
printf("%s\n", strings[0]);
/* (in future) it will display "amanaplanacanalpanama" */
free(strings[0]);
return 0;
}
char * removeSpaces(char * str[0]) // an ERROR occurs here
{
/* some code */
return -1; // in case of fault
}
Your code has two issues:
Your function declaration and definition conflicted. You don't have to specify
char *str[0], char *str is enough and it should match with your declaration at the top.
You are returning -1 instead of a pointer which is not a valid pointer in its form. If some fault occurs I would recommend you to return NULL instead.
-1 is an integer. But however, you can also use 0 instead, because that defaults to (void *)0 nothing but NULL.
change like this:
char * removeSpaces(char * str) // an ERROR occurs here
{
/* some code */
return NULL; // return NULL in case of fault instead of -1
}
When you declare a function, each parameter needs a type and a name. Your removeSpaces function takes a single parameter of type char *, so you'd declare it as
char * removeSpaces(char * str)
Remember, the function doesn't know that you'll be passing it the first element of an array; it just knows you'll give it a pointer to a string of characters.
It's also the convention in C to return a null pointer when its data is missing or would be invalid. So instead of returning -1 if there's an error, you should return NULL.
The declaration:
char * removeSpaces(char *);
Is different from the definition:
char * removeSpaces(char * str[0]);
Change the prototype:
char * removeSpaces(char *);
char *test = "hello";
test = change_test("world");
printf("%s",test);
char* change_test(char *n){
printf("change: %s",n);
return n;
}
im trying to pass a 'string' back to a char pointer using a function but get the following error:
assignment makes pointer from integer without a cast
what am i doing wrong?
A function used without forward declaration will be considered having signature int (...). You should either forward-declare it:
char* change_test(char*);
...
char* test = "hello";
// etc.
or just move the definition change_test before where you call it.
printf() prints the text to the console but does not change n. Use this code instead:
char *change_test(char *n) {
char *result = new char[256];
sprintf(result, "change: %s", n);
return result;
}
// Do not forget to call delete[] on the value returned from change_test
Also add the declaration of change_test() before calling it:
char *change_test(char *n);
You're converting an integer to a pointer somewhere. Your code is incomplete, but at a guess I'd say it's that you're not defining change_test() before you use it, so the C compiler guesses at its type (and assumes it returns an integer.) Declare change_test() before calling it, like so:
char *change_test(char *n);
thanks a bunch guys! didnt think i would have this problem solved by lunch. here is the final test class
/* standard libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* change_test(char*);
int main(){
char *test = "hello";
test = change_test("world");
printf("%s",test);
return (EXIT_SUCCESS);
}
char* change_test(char *n){
return n;
}