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
Related
I was getting realloc(): invalid next size for a program. So I just coded this to understand what's happening.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *inp;
printf("%lu ",sizeof(inp));
char *res = (char*)malloc(15*sizeof(char*));
printf("%lu ",sizeof(res));
res = "hello world";
printf("%lu\n",sizeof(res));
return 0;
}
And surprisingly it outputs 8 8 8. Can anyone explain why is it like that? Why is it 8 by default? And how malloc() effects size of inp?
sizeof(inp) gives you the size of pointer (8 bytes, 64-bits), not the storage under that pointer.
You are using sizeof.returns size in bytes of the object representation of type. Remember sizeof is an operator.
Now sizeof is returning here 8 a constant type of size_t
Why isn't it changing? because in all tha cases you are using the same type that is char *.
Here 8 bytes is the size of the character pointer that is 64 bit.
You can probably have a look at this-
printf("size of array of 10 int: %d\n" sizeof(int[10]));
This will give the output:40. 40 bytes.
And malloc will never affect the size of a char*. It still needs 64 bits to store an address of a dynamically allocated space from heap.
Is it possible to determine size of dynamically allocated memory in c?
There is no standard way to do this. You have to take this overhead on your own. You may find some extensions to the compiler that may accomplish this.
sizeof(inp) in your case is sizeof(pointer) and hence sizeof(char-pointer) on your system is 8 bytes which is a constant. While allocating memory using malloc() you would have specified the size so why do you need to get the size of the allocated space again?
And I see res is being initialized and not inp
****EDIT**** : The below post was written before the edit of the question.
You're missing stdlib.h, to the most, for function malloc() to work properly. After that,
Point 1:
char *res = (char*)malloc(15*sizeof(char*));
should be
char *res = malloc(15); //will also issue warning to resolve missing stdlib.h
Point no note: you should be allocating memory for chars, not char *s. Then , you should write sizeof(char), not sizeof(char *). Also, sizeof(char) is always 1 in C. So, can omit that part.
Please read: do not cast the return value of malloc() and family in C.
Point 2:
strings are not supposed to be assigned to already malloc()ed pointers. use strcpy() instead.
inp = "hello world";
should be
strcpy(inp, "hello world");
Otherwise, you'll overwrite the previously allocated memory, returned by malloc(). The assignment will overwrite the memory location held by inp, causing memory leak.
Point 3.
sizeof() operator returns a value of size_t. To print that, you need %zu format specifier.
Related, from C11 standard document, chapter §7.21.6.1, paragraph 7,
z
Specifies that a following d, i, o, u, x, or X conversion specifier applies to a
size_t or the corresponding signed integer type argument; or that a
following n conversion specifier applies to a pointer to a signed integer type
corresponding to size_t argument.
Then, to answer the query about the output, in all the cases, you're printing sizeof(inp) which is essentially sizeof(char *) and that value is fixed for a particular platform (8, in your case).
Just FYI, sizeof() is an operator, it's not a function. It returns the size of the datatype, not the amount of space pointed by the variable.
I'm wondering why this code can work. I'm assuming that the scanf is assigning the value to the address of a pointer to a char. I know this expression is undefined but why does printf using a pointer can print the correct value?
int main() {
char* p;
p = (char*)malloc(sizeof(char));
scanf("%c", &p);
printf("%c", p);
return 0;
}
And the result is
c
c
p is a variable that holds a memory address, and memory addresses are surely longer than 1 byte. If you store a char value in this variable, the previous value (the malloc'ed memory block) will be lost. printf just treates your variable as a char variable and prints its contents. If you suspected that the char would be stored in the memory block obtained by malloc, no it wasn't.
Try this:
int main() {
char *p, *q;
p = q = (char*)malloc(sizeof(char));
scanf("%c", &p);
printf("%c\n%c\n", p, *q);
return 0;
}
With the scanf(), you are storing (rather forcibly) one byte into a variable that is more than one byte (sizeof(char *), likely 8 bytes on a 64-bit machine). With the printf(), you then read one byte (sizeof(char), always one by standard) of this variable of size sizeof(char *) (more than one byte) and print it. Your variable p is more space than is needed to store a char. Since the sizes don't line up, you're not sure which byte of p will be read by printf(). It could be the byte that scanf() wrote, or it could be garbage data. You just got lucky and printf() read the same byte that scanf() wrote.
If all this sounds a bit uncertain, it is because it involves undefined behaviour. You are using scanf() and printf() improperly, so they make no guarantees as to what will happen. In short, don't do this.
printf() and scanf() don't perform any special type checking on the source/destination given as an argument. They use fancy pointer arithmetic with the arguments on the stack to figure out where to read/write things as needed. After the compiler builds it, printf() and scanf() will not complain. Your compiler should have given you warnings that the types of the arguments given do not match the format string. If it didn't, you either have a bad/old compiler or you should enable more warnings with the command line option -Wall.
To hopefully help explain the other answers, it looks as if you were aiming to do the following - compare the differences then take another look at the other answers and see if that helps, as I'm not sure you're yet clear about what's happening in your code.
int main() {
char* p = malloc(sizeof(char));
scanf("%c", p);
printf("%c", *p);
return 0;
}
In the book Learn C The Hard Way at excercise 15 there is suggestion to break program by pointing integer pointer at array of strings and using C cast to force it. How can I do it?
Here is a small example. the result depends on the endianness of your system and the size of int. I would expect the first or fourth character to change to the next character in the alphabet.
#include<stdio.h>
int main(void) {
char string[100] = "Somestring";
int *p;
/* Let p point to the string */
p = (int*)string;
/* modify a value */
(*p)++;
/* Let's see if any character got changed */
printf("%s", string);
return 0;
}
It should be pointed out that not all casts are safe and that the result could be implementation defined or undefined. This example is actually undefined, since int could have stricter alignment constraints than char.
When writing portable code you need to take great care when using casts.
The code above could break on any system where sizeof(int) is greater than the string length regardless of alignment issues. In this case, where the string has size 100, we wouldn't expect that to happen in a long while. Had the string been 4-7 bytes it could happen sooner. The jump from 32- to 64-bit pointers broke a lot of old code that assumed that pointers and int were the same size.
Edit:
Is there an easy fix to the alignment problem? What if we could somehow make sure that the string starts in an address that is also suitable for an int. Fortunately, that is easy. The memory allocation function malloc is guaranteed to return memory aligned at an address that is suitable for any type.
So, instead of
char string[100] = "Somestring";
we can use
char *string = malloc(100);
strcpy(string, "Somestring");
The subsequent cast is now safe alignment-wise and is portable to systems where int is smaller than 100.
Note that malloc is declared in stdlib.h, so we should add the following at the top of our code file:
#include<stdlib.h>
That's simply an abusive way of casting.
// setup the pointers to the start of the arrays
int *cur_age = ages;
char **cur_name = names;
What the author of that link meant by "to break program by pointing integer pointer at array of strings and using C cast to force it." He meant that you can write something like this int *cur_age = (int *)names; That is to cast a pointer to pointer to char to a pointer to int. You can do that in C, which allows you to cast from one type of pointer to another type of pointer; but be warned you need to know what you are doing.
Here the author wanted to show how to break a program by pointing a pointer to a wrong type. His example, however, is probably making you more confused rather than helping you to understand pointers.
To cast, use the cast operator: (type)expression. For example, to cast an expression of type double to int:
(int)sqrt(2);
In your specific case, cast names to int* (the type of cur_age) to break the program:
cur_age = (int*)names;
To point incompatible pointer in c you only need to cast it to void.
//array of string declaration
char aStr[50][50];
Int *pint;
//do whatever you need with string array
pint = (*int)(*void)aStr;
I'm writing this from my cell phone.
if you increment your pointer past the allocated memory, you might end up in your program stack and change value to it.
I was getting realloc(): invalid next size for a program. So I just coded this to understand what's happening.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *inp;
printf("%lu ",sizeof(inp));
char *res = (char*)malloc(15*sizeof(char*));
printf("%lu ",sizeof(res));
res = "hello world";
printf("%lu\n",sizeof(res));
return 0;
}
And surprisingly it outputs 8 8 8. Can anyone explain why is it like that? Why is it 8 by default? And how malloc() effects size of inp?
sizeof(inp) gives you the size of pointer (8 bytes, 64-bits), not the storage under that pointer.
You are using sizeof.returns size in bytes of the object representation of type. Remember sizeof is an operator.
Now sizeof is returning here 8 a constant type of size_t
Why isn't it changing? because in all tha cases you are using the same type that is char *.
Here 8 bytes is the size of the character pointer that is 64 bit.
You can probably have a look at this-
printf("size of array of 10 int: %d\n" sizeof(int[10]));
This will give the output:40. 40 bytes.
And malloc will never affect the size of a char*. It still needs 64 bits to store an address of a dynamically allocated space from heap.
Is it possible to determine size of dynamically allocated memory in c?
There is no standard way to do this. You have to take this overhead on your own. You may find some extensions to the compiler that may accomplish this.
sizeof(inp) in your case is sizeof(pointer) and hence sizeof(char-pointer) on your system is 8 bytes which is a constant. While allocating memory using malloc() you would have specified the size so why do you need to get the size of the allocated space again?
And I see res is being initialized and not inp
****EDIT**** : The below post was written before the edit of the question.
You're missing stdlib.h, to the most, for function malloc() to work properly. After that,
Point 1:
char *res = (char*)malloc(15*sizeof(char*));
should be
char *res = malloc(15); //will also issue warning to resolve missing stdlib.h
Point no note: you should be allocating memory for chars, not char *s. Then , you should write sizeof(char), not sizeof(char *). Also, sizeof(char) is always 1 in C. So, can omit that part.
Please read: do not cast the return value of malloc() and family in C.
Point 2:
strings are not supposed to be assigned to already malloc()ed pointers. use strcpy() instead.
inp = "hello world";
should be
strcpy(inp, "hello world");
Otherwise, you'll overwrite the previously allocated memory, returned by malloc(). The assignment will overwrite the memory location held by inp, causing memory leak.
Point 3.
sizeof() operator returns a value of size_t. To print that, you need %zu format specifier.
Related, from C11 standard document, chapter §7.21.6.1, paragraph 7,
z
Specifies that a following d, i, o, u, x, or X conversion specifier applies to a
size_t or the corresponding signed integer type argument; or that a
following n conversion specifier applies to a pointer to a signed integer type
corresponding to size_t argument.
Then, to answer the query about the output, in all the cases, you're printing sizeof(inp) which is essentially sizeof(char *) and that value is fixed for a particular platform (8, in your case).
Just FYI, sizeof() is an operator, it's not a function. It returns the size of the datatype, not the amount of space pointed by the variable.
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.