usage of strdup - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s = strdup("foo");
printf("%s\n", s);
getchar();
return 0;
}
Looks pretty harmless, doesn't it ?
But my IDE, which is Dev-C++, gives my the following warning:
warning: assignment makes pointer from integer without a cast
The warning disappears if you would change the code like this:
char *s;
s = (char*)strdup("foo");
Can anyone help me explain this?

You're using Dev-C++, but strdup is not part of the C or C++ standard, it's a POSIX function. You need to define the proper (according to your IDE's documentation) preprocessor symbols in order for strdup to be declared by the header file ... this is necessary in order for the header file not to pollute the name space when included into conforming C or C++ source files.
For a simple portable alternative, consider
char* mystrdup(const char* s)
{
char* p = malloc(strlen(s)+1);
if (p) strcpy(p, s);
return p;
}
Or, if you know strdup is actually in the library, you can copy its declaration from string.h into your own source file or header ... or use the simpler declaration from the man page:
char *strdup(const char *s);

That's not right. strdup returns char * already. Something else is wrong. Probably because you did not include the right header file that declares the true return type for this function.
#include <string.h>

You're missing #include <string.h>. In the absence of function signatures, strdup is assumed by the compiler to return an int, hence the warning.

man strdup
you will get following things
#include<string.h>
char* strdup(const char * s);
so strdup() returns char* there shuld not be any problem
Actually in your case it takes implicit declaration of strdup() so by default return type is int hence you get this warning
Either include<string.h>
or
give forward declaration char* strdup(const char *);
Also don't forget to free(s) in last when all usage are done

Related

How to create wrappers to library functions with original name?

I found this question very interesting: How to force compilation error if function return value is not checked?
It's about enforcing compilation errors if you do not check the return value. I wrote an answer to that question where you can use gcc extensions like this:
__attribute__ ((warn_unused_result)) int foo (void)
{
return 5;
}
to enforce a warning and the compile with -Werror=unused-result to make the compiler generate an error if you don't use the return value somehow.
Now I would like to create wrapper functions to the regular standard functions. An idea is to rename them like this:
__attribute__ ((warn_unused_result)) realloc_wrapper(void *ptr, size_t new_size)
{
return realloc(ptr, new_size);
}
But the problem is that this forces me to use a different name, which would cause a lot of search and replace. Granted, this can be done automatically, but still. Preferably, I would like to be able to create a header that I can use instead of a standard C header for any program. One use case is when debugging a big program. Then this would instantly point me to potential causes of bugs.
TL;DR
So in short, I want to be able to take this program:
#include <stdlib.h>
int main(void)
{
char *ptr;
realloc(ptr, 42);
}
and change it to:
// Replaced stdlib with a custom header
#include <mystdlib.h>
int main(void)
{
char *ptr;
realloc(ptr, 42);
}
and then the line with realloc should generate a warning.
I might add that I'm ok with a solution that isn't 100% perfect. The intended use is for debugging and not production code.
EDIT:
I just noticed that realloc was a bad choice, since it seems to already have this declaration by default, but I used PSkocik and made it work for fgets.
A straightforward solution would be to shadow the function with an identically named macro. (I'll use puts as an example, because, as you've mentioned, realloc is already usually declared with warn_unused_result)
/*begin your header:*/
#include <stdio.h>
__attribute ((__warn_unused_result__)) static inline
int puts_wrapper(char const*X)
{
return (puts)(X);
}
#define puts(X) puts_wrapper(X)
/*end your header*/
int main(void) { puts("hello, world"); }
(The parentheses around puts aren't necessary but they allow you to move the define before the puts_wrapper definition if you wanted to.)
Alternatively, you could simply redeclare the function with the warn_unused_result attribute added (works on both gcc and clang).
/*begin your header*/
#include <stdio.h>
__attribute ((__warn_unused_result__)) int puts(char const*);
/*end your header*/
int main(void) { puts("hello, world"); }

How to use scanf() without including stdio.h

Is there any possible methods to write a C program without including stdio.h as a header file. It was suggested that it can be implemented by declaring extern int scanf(char* format, ...);
#include <stdio.h> //I want this same code to work without including this line
int main ()
{
char str [80];
scanf ("%s",str);
return 0;
}
You can declare the scanf function with:
extern int scanf(const char *format, ...);
The extern keyword is optional but I like to include it as a reminder of the fact that the function is defined elsewhere.
Your example would then look like:
extern int scanf(const char *format, ...);
int main ()
{
char str [80];
scanf ("%s",str);
return 0;
}
In C-89, that code would compile without the #include, as function prototypes are optional.
Having said which, it comes under the list of 'really bad things to do' - scanf may be a macro, it might have one or more required parameters, ...
So you can do it, but it's like driving at night without any lights. You're liable to crash, even if you think you know the road.

Why does this code not compile?

Could anyone please explain why this code compiles :
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv [])
{
FILE *ptr;
char string[10] = "Testing";
ptr = fopen("C:\\Users\\Jordan\\Desktop\\Hello.txt", "wb");
fwrite(string,sizeof(string[0]), sizeof(string)/sizeof(string[0]), ptr);
}
Yet this does not : Gives an Error C2065:'string' : undeclared identifer
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv [])
{
FILE *ptr;
ptr = fopen("C:\\Users\\Jordan\\Desktop\\Hello.txt", "wb");
char string[10] = "Testing";
fwrite(string,sizeof(string[0]), sizeof(string)/sizeof(string[0]), ptr);
}
I am using Visual Studio 2010 on a Windows 7 Machine.
Thanks
Visual Studio uses the old C89/90 C. In that older C version, you can't mix declarations and code.
All your declarations must go on top. That's why the second example fails to compile.
// This a declaration
FILE *ptr;
// This is code
ptr = fopen("C:\\Users\\Jordan\\Desktop\\Hello.txt", "wb");
// This is another declaration. Not Allowed in C89/C90!!!
char string[10] = "Testing";
In (the C89 version of) C, all variables must be declared at the top of the block (the function, in this case). In your first example, you're doing that, in your second one you're not.
If you saved this file with a .c extension the compiler is interpreting it as a C source file, and since VC++ support for C is for C89, the C89 rules for variable declaration apply; in particular, in C89 you must declare all the local variables at the beginning of their block.

pointers in c (beginner)

I just started to look at C, coming from a java background. I'm having a difficult time wrapping my head around pointers. In theory I feel like I get it but as soon as I try to use them or follow a program that's using them I get lost pretty quickly. I was trying to follow a string concat exercise but it wasnt working so I stripped it down to some basic pointer practice. It complies with a warning conflicting types for strcat function and when I run it, crashes completly.
Thanks for any help
#include <stdio.h>
#include <stdlib.h>
/* strcat: concatenate t to end of s; s must be big enough */
void strcat(char *string, char *attach);
int main(){
char one[10]="test";
char two[10]="co";
char *s;
char *t;
s=one;
t=two;
strcat(s,t);
}
void strcat(char *s, char *t) {
printf("%s",*s);
}
Your printf() should look like this:
printf("%s",s);
The asterisk is unnecessary. The %s format argument means that the argument should be a char*, which is what s is. Prefixing s with * does an extra invalid indirection.
You get the warning about conflicting types because strchr is a standard library routine, which should have this signature:
char * strcat ( char * destination, const char * source );
Yours has a different return type. You should probably rename yours to mystrchr or something else to avoid the conflict with the standard library (you may get linker errors if you use the same name).
Change
printf("%s",*s);
to
printf("%s",s);
The reason for this is printf is expecting a replacement for %s to be a pointer. It will dereference it internally to get the value.
Since you declared s as a char pointer (char *s), the type of s in your function will be just that, a pointer to a char. So you can just pass that pointer directly into printf.
In C, when you dereference a pointer, you get the value pointed to by the pointer. In this case, you get the first character pointed to by s. The correct usage should be:
printf( "%s", s );
BTW, strcat is a standard function that returns a pointer to a character array. Why make your own?
Replacing *s with s won't append strings yet, here is fully working code :
Pay attention to function urstrcat
#include <stdio.h>
#include <stdlib.h>
/* urstrcat: concatenate t to end of s; s must be big enough */
void urstrcat(char *string, char *attach);
int main(){
char one[10]="test";
char two[10]="co";
char *s;
char *t;
s=one;
t=two;
urstrcat(s,t);
return 0;
}
void urstrcat(char *s, char *t) {
printf("%s%s",s,t);
}
pointers are variable which points to address of a variable.
#include "stdio.h"
void main(){
int a,*b;
a=10;
b=&a;
printf("%d",b);
}
in the follwing code you will see a int 'a' and a pointer 'b'.
here b is taken as pointer of an integer and declared by giving'' before it.'' declare that 'b' is an pointer.then you will see "b=&a".this means b is taking address of integer "a" which is keeping value 10 in that particular memory and printf is printing that value.

c pass a string to function then return a string

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *abc = "abc";
char *new_str;
new_str = getStr(&abc);
printf("%s", abc);
}
char *getStr(char *str)
{
printf(str);
return str;
}
What's wrong with the code above?
A bunch of small things:
You're passing &abc to getStr(). &abc is a pointer to the variable that is holding your string. Its type a pointer to a pointer, and that's incompatible with the char *str argument of getStr().
Your getStr() is defined after it is used. You either need to move its definition to before main() or add a prototype before main().
The type of a string literal like "abc" is const char *. You're defining a variable of type char *, which is dubious (since it would allow you to modify a string literal, which is not allowed).
here is a working version:
#include <stdio.h>
#include <stdlib.h>
char *getStr(char *str);
int main(void)
{
char *abc = "abc";
char *new_str;
new_str = getStr(abc);
//printf("%s", *abc); don't really need this
}
char *getStr(char *str) {
printf("%s", str);
return str;
}
Here's a list of problems with the old one:
No prototype for your function getStr.
You can't do printf(str) you need a "%s" as an additional param.
You need to change: new_str = getStr(&abc) to new_str = getStr(abc)
A C string is a pointer to a character that begins a sequence of characters that end with a null byte. The variable abc perfectly fits this definition.
Also, abc is of type pointer to character. You are passing the address of abc, ie getStr will be receiving the address of a pointer to a character--so getStr's only argument should be of type pointer to pointer to character. The types do not match up.
EDIT: Also, getStr is called before it's declared. Your compiler may allow this, but it's bad practice for many reasons. You should declare it or define it before it is used. If you are using gcc as your compiler, always use
gcc -ansi -Wall -pedantic
Those three flags will conform to ANSI standards, and it would either yell at you for the above issues or not compile.
Your getStr function takes a char *, but that's not what you're passing it - you're passing the address of the pointer, instead of passing it the actual pointer.
Change:
new_str = getStr(&abc);
to:
new_str = getStr(abc);
and I think it'll work.

Resources