I'm trying to understand how pointers to pointers work and I came out with this example, and it compiles fine. But, when it is executed, I get a segmentation fault.
PS: I don't want f1() to return char *.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int f1(char **str_);
int main(int argc, char **argv)
{
char *str = NULL;
f1(&str);
printf("str : %s\n", *str);
str = realloc(str, (size_t) 0);
assert(str == NULL);
return 0;
}
int f1(char **str_)
{
if ((*str_ = realloc(*str_, sizeof(char) * 12)) == NULL)
{
fprintf(stderr,"realloc() failed\n");
exit(3);
}
(*str_) = "hello there";
return 0;
}
What is wrong with the code?
You either need to turn on more warnings in your compiler or get a better compiler. When I compile your code, I get the warnings:
mem.c: In function ‘main’:
mem.c:12: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
mem.c:12: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
mem.c: At top level:
mem.c:7: warning: unused parameter ‘argc’
mem.c:7: warning: unused parameter ‘argv’
I'm not quite sure why the warning on line 12 is repeated, but both GCC 4.2 and 4.6.1 on MacOS X 10.7 give it twice. The warnings about argc and argv are a good reason for using int main(void) when you are not using the command line arguments; they aren't a big problem.
The warning (really, an error) about %s and int vs char * is sufficient to account for your crash - it is not, however, the only issue with the code. In fact, there is also:
an incipient memory leak,
an actual leak,
a place where you are (accidentally) relying on undefined behaviour, and
a place where you're relying on implementation-defined behaviour which may not match your expectations.
Your code annotated:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int f1(char **str_);
int main(int argc, char **argv)
{
char *str = NULL;
f1(&str);
printf("str : %s\n", *str);
str = realloc(str, (size_t) 0); /* (3) Undefined behaviour */
assert(str == NULL); /* (4) Implementation-defined behaviour */
return 0;
}
int f1(char **str_)
{
if ((*str_ = realloc(*str_, sizeof(char) * 12)) == NULL) /* (1) Incipient leak */
{
fprintf(stderr,"realloc() failed\n");
exit(3);
}
(*str_) = "hello there"; /* (2) Actual leak */
return 0;
}
Discussing these in the numbered sequence:
The incipient leak arises if the memory reallocation fails. *str is the only place where the previous value of the pointer to the allocated memory is stored, and if realloc() fails, it returns 0 (null pointer) but does not release the old memory, but you no longer have a pointer to the old memory.
The fix:
char *new_mem = realloc(*str, 12);
if (new_mem == 0)
...error handling...
*str = new_mem;
Rule of thumb: do not assign the return value from realloc() to the variable that is its first argument.
The actual leak arises because you assign the pointer to a string constant over the pointer to the newly allocated memory. The simplest fix is to use strcpy(), though you need to add #include <string.h> when you do so. You would also, normally, make sure you allocate just enough space for the string you are going to copy, leading to:
char const hello[] = "hello there";
char *new_mem = realloc(str, sizeof(hello));
//char *new_mem = realloc(str, strlen(hello)+1);
if (new_mem == 0)
...handle error...
*str = new_mem;
strcpy(new_mem, hello);
In this example, I can use sizeof(hello) because the size of a string includes the null terminator, and because the actual array definition is in scope. If the string to be copied was passed into the function as a pointer, then the alternative using strlen(hello)+1 is correct (and using sizeof() is incorrect), even though it requires a runtime computation of the length instead of a compile time computation as shown.
The undefined behaviour arises because of the memory leak at (2). You try to realloc() a string constant, not the pointer returned by realloc(). This leads to undefined behaviour; it could crash (because realloc() tries to write control information into read-only memory) or it might simply mess up the memory system, leading to a crash some time later.
The fix for this is the correction for item (2).
The implementation-defined behaviour arises because the C standard says:
§7.20.3 Memory management functions ¶1: [...] If the size of the space requested is zero, the behavior is implementation defined:
either a null pointer is returned, or the behavior is as if the size were some
nonzero value, except that the returned pointer shall not be used to access an object.
You are asserting that your implementation will choose the first option, but it might choose the second. The fix is to remove the unwarranted assertion.
So, that's a total of 5 problems in the code, only one of which a compiler is likely to help you with.
The first line of main() sets the variable str to NULL and passes a pointer to it to f1.
f1 runs perfectly fine. The outcome of f1 is that the variable str inside of main is now a pointer to a space in memory holding the string (literal) "hello there".
Your next line, the printf, segfaults. Why? Because you are trying to print *str (note the asterisk here!!) as a string (format specifier %s). What is *str when iterpreted as a string? Whatever "address" is denoted by "hell" probably (at least on a 32-bit machine). Doubtful that address is in your process space.
Classic segfault.
Try passing str rather than *str to printf.
That will work, see http://codepad.org/Mh00txen
There are other issues with the code, e.g. the realloc of 12 chars in f1 does nothing except cause a memory leak because you immediately reassign that pointer to point to a string literal, but that is not the cause of your segfault.
Related
Having this:
#define _DEFAULT_SOURCE 1
#include <stdio.h>
#include <string.h>
int main(){
char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
while((token=strsep(&org,",")))
printf("Token: %s\n",token);
}
gives err (incompatible pointer type):
/usr/include/string.h:439:14: note: expected ‘char ** restrict’ but argument is of type ‘char (*)[47]’
extern char *strsep (char **__restrict __stringp,
I know it is different type (one has memory initialized -> org[], but the function wants pointer without any memory initialized), but they have the same behaviour, so why it complain anyway?
And can somone explain me, what is the meaning of this keyword restrict or __restrict in case of *strsep (char **__restrict __stringp, (on the other hand, I assume the __stringp is not a internal datatype (because of double underscores) but only a fancy variable name).
Edit:
I think an array is stored in stack, but the strsep wants a pointer that points to a heap, which could be done with having org allocated with malloc and then memcpy, or even better, copy the string via strdup (which does internally memcpy). But anyway, way does strsep wants pointer that points to heap and not to stack? Both are just pointers, point only to different addresses, but that should not mind.
The strsep function requires the address of a modifiable pointer as its first argument (or NULL, in which case it does nothing); you are passing it the (fixed) address of an array. You can fix this by declaring a separate char* variable and assigning to that the (address of the) org array:
int main()
{
char* token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
char* porg = org; // "porg" is a MODIFIABLE pointer initialized with the start address of the "org" array
while ((token = strsep(&porg, ",")))
printf("Token: %s\n", token);
return 0;
}
From the Linux manual page (bolding mine):
If *stringp is NULL, the strsep() function returns NULL and does
nothing else. Otherwise, this function finds the first token in the
string *stringp, that is delimited by one of the bytes in the string
delim. This token is terminated by overwriting the delimiter with a
null byte ('\0'), and *stringp is updated to point past the token. In
case no delimiter was found, the token is taken to be the entire
string *stringp, and *stringp is made NULL.
On the meaning and use of the restrict keyword, maybe this will help: Realistic usage of the C99 'restrict' keyword?.
Address of the array references the place where the array starts, it has only the different type - pointer to the array. It is not pointer to pointer.
char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
char *pointer = org;
while((token=strsep(&pointer,",")))
/* ... */
You cant cast reference to array to double pointer.
restrict it a quite advanced topic. It promises the compiler that if the object referenced by pointer is modified, the access to this object can be only done by this pointer. It helps the compiler in the code optimisations
Generally speaking I would not expect you to use this qualifier before you get proficient in the C language.
#include <stdio.h>
#include <string.h>
int main()
{
char org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
char *token = strtok(org, ",");
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok(NULL, ",");
}
}
I think you should take a look at this page : Restrict type qualifier
First post here, I've used this site for years but this dilemma is really annoying. So when I run this C code through the VS2015 Developer Command prompt with the C compiler:
#include <stdio.h>
#include <string.h>
int main(){
char* ptr = NULL;
const char* pt2 = "hello";
strcpy(&ptr, pt2);
printf("%s",&ptr);
return 0;
}
I get these warnings:
midterm_c.c(35): warning C4047: 'function': 'char *' differs in levels of indirection from 'char **'
midterm_c.c(35): warning C4024: 'strcpy': different types for formal and actual parameter 1
midterm_c.c(36): warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'char **'
Yet when I run it, it prints "hello", which shouldn't happen because it doesn't make sense to use the reference operators on the ptr variable. But when I run this code without them:
char* ptr = NULL;
const char* ptr2 = "hello";
strcpy(ptr, ptr2);
printf("%s",ptr);
return 0;
I get no warnings, successfully compiles, yet when I run it the program crashes even though this should work properly. I'm getting really frustrated because this doesn't make any sense to me and one of the reasons why I'm really hating C right now. If anyone has any idea how this is happening I'd really appreciate it. Thank you.
In your working code, you basically just treated part of your stack as a string buffer; it's flagrantly illegal by the standard, but it happens to work because you don't read from anything you stomp on after the stomping.
You're correct that passing a char** to strcpy makes no sense, but what ends up happening is that it writes to the char* variable itself (and some neighboring memory if it's a 32 bit program), treating it as an array of char (after all, an eight byte pointer has enough room for a seven character string plus NUL terminator). Effectively, your code is incorrect code that still happens to behave like correct code, since this:
char* ptr = NULL;
const char* pt2 = "hello";
strcpy(&ptr, pt2);
printf("%s",&ptr);
compiles to code that behaves almost exactly like this (aside from the warnings):
char ptr[sizeof(char*)]; // Your char* behaves like an array
const char* pt2 = "hello";
strcpy(ptr, pt2);
printf("%s", ptr);
When you don't take the address of ptr, you pass a NULL pointer to strcpy, which crashes immediately (because you can't write to a NULL pointer's target on almost all systems).
Of course, the correct solution would be to make ptr point to allocated memory, either global, automatic, or dynamically allocated memory. For example, using a stack buffer, this would be legal:
char buf[8];
char *ptr = buf; // = &buf[0]; would be equivalent
const char* pt2 = "hello";
strcpy(ptr, pt2);
printf("%s", ptr);
although it would be rather pointless, since ptr could just be replaced with buf everywhere and ptr removed:
char buf[8];
const char* pt2 = "hello";
strcpy(buf, pt2);
printf("%s", buf);
First of all, you don't know how to use strcpy. The first parameter needs to point to space available to copy into, it doesn't allocate space for you.
Your first example probably only "works" because it is copying into stack-space. This is undefined behavior and will cause all kinds of problems.
Your second example (the more correct one) will generally cause a segfault because you are trying to copy into (or read from) a null address.
You're writing to random memory, which is undefined behavior. This means that according to the C standard, the compiler is allowed to generate code that does literally anything, including but not limited to:
Printing "hello".
Printing random gibberish.
Crashing.
Corrupting some other variable in your app.
Ripping a hole in the fabric of space-time, causing an invasion by evil space lemurs from the fifth dimension that ruin the market for Kopi Luwak coffee by causing a glut in the supply.
Tl;dr: Don't do that.
You need to allocate memory for ptr variable (malloc). Then, a usefull function is strdup().
It take a string, allocate the good memory's space for a new string and copy the content of the source in it before returning the new string.
You can do:
ptr = strdup(pt2);
The documentation: http://manpagesfr.free.fr/man/man3/strdup.3.html
I decided to make a reverse(s) function in C and in the process, I encountered 2 warning messages during compilation.
alexander#debian:~/Dropbox/GitRepo/M2MPL/text$ make reverse
cc reverse.c -o reverse
reverse.c: In function 'reverse':
reverse.c:29:2: warning: return makes integer from pointer without a cast [enabled by default]
reverse.c:29:2: warning: function returns address of local variable [enabled by default]
alexander#debian:~/Dropbox/GitRepo/M2MPL/text$
Since they were warnings I tried to ignore them and run the program, when I input an array of characters Dropbox using scanf("%s", str1);, the result appeared as Segmentation Fault.
alexander#debian:~/Dropbox/GitRepo/M2MPL/text$ ./reverse
Enter a string to reverse: Dropbox
Segmentation fault
alexander#debian:~/Dropbox/GitRepo/M2MPL/text$
Here's my implementation of the reverse(s) function:
/* reverse: returns a reversed string of s */
char reverse(char s[])
{
int i, len=strlen(s);
char result[LIMIT];
for (i = len; i >= 0; --i) {
result[len-i] = s[i];
}
return result;
}
FULL CODE HERE!
I need help to know why I got a Segmentation fault instead of xobporD as a result and if possible, a suggestion to fix this problem.
First of all:
The compiler does not warn you just for fun. You shouldn't be surprised that your program crashes if you ignore compiler warnings.
You return the pointer to an automatic variable that goes out of scope at the end of the function. The pointer returned to the caller is not valid since it points to an object that no longer exists after the reverse function returns.
Another problem is that the first character that you copy is the '\0' so your resulting string is empty. You need to reverse the characters of the string, but still put the '\0' at the end of the string.
The first warning means that the return type indicated by the signature of the reverse function does not match the type of the variable that you are actually returning. The expected type is char, and you are returning a char * (because result decays to such a pointer). So the compiler transforms the pointer into an integer (char), which is usually not what's intended by the programmer.
The second problem is that you are returning the address of a local variable, and that variable is no longer available after the function returns, because of the way automatic storage works. If you want to return a pointer to some data, it must be allocated either globally (declared static inside the function or declared globally), or it must be dynamically allocated.
There are a few flaws in the question code.
It is likely that the return type should be 'char *' rather than 'char'.
Attempting to return local stack memory to the caller.
The result string is likely missing a string termination character.
The following code fix the above. It returns the string in allocated 'heap' memory to the caller. (The caller should free() the memory when it is no longer needed.):
/* reverse: returns a reversed string of s */
char *reverse(char *s)
{
int i, len=strlen(s);
char *result = malloc(len+1);
if(result)
{
result[len] = '\0';
for(i = len; i >= 0; --i)
result[len-i] = s[i];
}
return(result);
}
when i'm tryin' to use malloc with string pointers to scan, it's givin' a segmentation fault
main(){
char *a;
a = (char)malloc(50);
printf("enter a string\t");
scanf("%s", a);
printf("%s\n", a);
}
a = (char)malloc(50);
Here, you meant to cast its type to char * instead of char.
Note that it's better not to cast the return type of malloc. See Do I cast the result of malloc?
Your main problem, apart from your using scanf is that you're casting a pointer (which is size 4 or 8 on 32 or 64 bit systems respectively) to a char, which is guaranteed to be size 1 as per standard. Do not ignore compiler warnings. You should've seen something along the lines of:
warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
a = (char) malloc(10);
warning: assignment makes pointer from integer without a cast [enabled by default]
a = (char) malloc(50);
Casting a pointer type to char, only to assign it to a pointer variable makes no sense. If you want to make it absolutely clear that you are allocating enough memory to accomodate N chars, then you could write:
a = malloc(50 * sizeof(char));
//or better still
a = malloc(50 *sizeof *a);//50 times the size of whatever type a is pointing to...
But a char is always size 1, like I said before. Anyway: I set about fixing the code you posted:
The following copy-pasted code works just fine, provided you don't enter more than 49 chars:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char *a = malloc(50);
if (a == NULL) return EXIT_FAILURE;//<-- no memory available
printf("enter a string\t");
scanf("%s", a);
printf("%s\n", a);
free(a);//<== be tidy, free your memory, though here, it's a bit redundant
return 0;
}
But really, look into alternatives to scanf, and never cast the pointer returned by malloc in C. C++ is a different matter.
Also, check for NULL pointers, to be safe.
Lastly: Don't ignore compiler warnings.
copy-paste & test here
you can provide stdin input at the bottom right hand side of the page, it'll print the string you provided
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a="9jhjhi";
printf("%s",a);
}
Why does this throw a segmentation fault? What happens behind the screens?
You need to use char *a = "...".
printf when passed %s will run through a string looking for a 0/NULL byte. In your case you are not assigning a string literal to a, and in fact your compiler should have thrown a warning that you were trying to initialize a char from a pointer.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *a="9jhjhi";
printf("%s",a);
}
Your error is that
char a="9jhjhi";
should be
char *a="9jhjhi";
What happens is undefined behavior - so anything could happen.
Your assigning a string literal to a char, so your a will contain a pointer(to the beginning of that string) converted to a char - whatever that'll be.
%s conversion in printf assumes you pass it a string, which must be a char* pointing to a sequence of chars ending with a 0 terminator. You passed it a char, which certainly does not meet those requirements, so it's quite undefined what'll happen - a crash could be common.
You should also return something from the main() method - it's declared to return an int after all.
a is initialized to a (cast to integer and truncated because char is 3 or 7 bytes too small) pointer that points to a char array (propably somewhere in ROM). What follows is undefined, but it's propably like this: When you pass it to printf with a %s in the format string, it takes the value of a (something in 0-255) and 3 (or 7) unrelated bytes from the stack, gets some bogus address and wreaks havok by accessing someone else's memory.
Use char *a = ....
C does not have strings as in String b = new String();
C has arrays of type char.
So char a="123123" should be a character array.
You aren't using anything from stdlib.h in that code either so there is no reason to #include it.
Edit: yeah, what nos said too. An array name is a pointer.
You mean
char *a = "9jhjhi";
If this compiles without warnings, your compiler settings are messed up. The warnings from gcc show plainly what's happening:
test.c: In function ‘main’:
test.c:5: warning: initialization makes integer from pointer without a cast
test.c:6: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
The string literal is interpreted as a pointer, which is converted (and truncated) to a char.
Then the char is sent into printf as a number, but interpreted as a string. Since it's not null-terminated in any way, printf probably overruns memory when racing through that "string".
When you declare char a without a pointer symbol, you are only allocating enough space on the stack for a single character.
Strings in C are represented by a char array, or a pointer to a char array, terminated by the null character '\0'. But if you use a literal string, the compiler takes care of all of that for you.
Here's how you can get your code to work, then:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *a = "9jhjhi";
printf("%s",a);
}
First of all, you're trying to save an entire string into a single char variable. Use char array (char[size]) instead. You may also want to terminate the string with "\0".
You could remove this error in two ways.
1.char * p="karthik A"
2.char [ ]p="karthik A"