I read a unit test, that checks for invalid free or double-free:
int main() {
char *a = (char*) my_malloc(200);
char *b = (char*) my_malloc(50);
char *c = (char*) my_malloc(200);
char *p = (char*) my_malloc(3000);
(void) a, (void) c;
memcpy(p, b - 200, 450);
my_free(p + 200);
printstatistics();
}
Why do we need to cast char* to void and what happens in memory when we do this cast?
(void) a, (void) c;
is a common way to get rid of compiler warnings about unused variables. Since those two variables are initialised only and not used later, most compilers would issue warnings about it. Since this is apparently some kind of a test of memory allocation they are not used on purpose, so someone decided to silence warnings.
Related
Consider the following code:
struct ns_test{
char *str;
};
struct ns_test *ns_test_alloc(char *str){
struct ns_test *nt = malloc(sizeof(*nt));
nt->str = str;
return nt;
}
const char *ns_test_get_str(struct ns_test *tst){
return tst->str;
}
void ns_test_release(struct ns_test* tst){
free(tst);
}
void ns_test_set_char(struct ns_test *tst, size_t i, char c){
tst->str[i] = c;
}
int main(void){
char arr[] = "1234567890";
struct ns_test *ns_test_ptr = ns_test_alloc(arr);
const char *str = ns_test_get_str(ns_test_ptr);
printf("%s\n", str); //1234567890
ns_test_set_char(ns_test_ptr, 4, 'a');
printf("%s\n", str); //1234a67890
}
The question is: Is the behavior of the code undefined?
I think it is.
The Standard specifies at 6.7.3(p6):
If an attempt is made to modify an object defined with a
const-qualified type through use of an lvalue with non-const-qualified
type, the behavior is undefined.
So to avoid this sort of UB we need const char *ns_test_get_str(struct ns_test *tst) to copy the char *str instead. But the main point was to avoid the copying and restrict the modification to the only void ns_test_set_char(struct ns_test *tst, size_t i, char c) which may do some sanity checks or something else prior.
The key here is "an object defined with a const-qualified type". What matters is how you define (IOW, "allocate memory for") the object being pointed at. If the "object" was not "created" as const, then it does not matter how many const or non-const pointers and references you use - you can still modify it.
So,
const int i = 0;
int *p = (int*)&i;
*p = 1;
is UB.
While
int i = 0;
const int *cp = &i;
int *p = (int*) cp;
*p = 1;
is fine.
I suspect this would even work with new:
const int *cp = new const int(0);
int *p = (int*) cp;
*p = 1;
is technically UB.
It does compile w/o warning on cpp.sh, but that does not mean much.
Update: as Christian Gibbons pointed out, the language in the question is C, so the part about new operator does not apply. malloc() and friends are never const.
To expand this a little - one possible reason for writing the standard this way is to give the compiler freedom to use read-only memory for const values. In that case, writing to such locations becomes a crash or a noop. In other words, UB.
I am a newbie to C and it took me 2 hours to figure out the problem.
void helper(char* a, char* b){
a = malloc(strlen(b));
memcpy(a, b, strlen(b));
printf("%s %s\n", a, b);
}
int main(){
char* b = "hello";
char* a;
helper(a, b);
printf("%s", a);
}
While a is always null. Is there anything I missed?
In main(), a and b are pointers.
helper(a, b); gives a copy of pointer a and a copy of pointer b to helper() as part of the call to helper().
The function completes.
The a in main() is not updated/changed by the call helper(a, b). Neither is b changed.
Code needs a new approach of which there are several good ones. Example: Use the return value of helper2().
char *helper2(const char *source);
int main(void) {
const char* b = "hello";
char* a = helper2(b);
printf("<%s>", a);
free(a);
}
Now create helper2(). Code template follows:
#include <...> // whats includes are needed.
#include <...>
char *helper2(const char *source) {
size_t size_needed = ....; // length + 1 for the null character
char *destination = ...' // allocate
if (destination ...) { // Successful allocation?
memcpy(destination, ...., ...); // copy - include null character
}
return ... // What should be returned here?
}
You've missed the fact that main() passes a copy of a to helper() by value. So the a in helper() is a completely different variable (even though you've given it the same name) - it has a different address.
The change of a in helper() therefore does not affect the a in main() at all.
Regardless of what helper() does, main() exhibits undefined behaviour. a is uninitialised, so passing its value to helper() gives undefined behaviour. Passing it to printf() gives undefined behaviour for the same reason.
The printf() call in helper() also has undefined behaviour, since %s causes printf() to expect a string terminated by a '\0', but the memcpy() call has not copied such a thing to a. Practically, printf() will probably keep stepping from a through random memory until it happens to find a byte with zero value. This may result in garbage output or (if there is no such byte in memory) an obscure program crash.
A partial fix of your code would be to make the change of a in helper() visible to main(). For example;
/* Danger: This code still has undefined behaviour */
void helper(char **a, char* b)
/* note usage of extra * on every usage of a in this function */
{
*a = malloc(strlen(b));
memcpy(*a, b, strlen(b));
printf("%s %s\n", *a, b);
}
int main()
{
char* b = "hello";
char* a;
helper(&a, b); /* note use of ampersand here */
printf("%s", a);
free(a); /* a has been malloc()ed, so free() it */
/* using a here will give undefined behaviour, since it is free()d */
}
This code makes the changes to a in helper() visible to main(), by use of pointers.
The problem with this partially fixed code code is that %s still causes printf to expect that a to be terminated with a trailing '\0', but the memcpy() does not copy such a trailing '\0'. So both printf() calls (in both helper() and main()) still have undefined behaviour.
To fix this, we need to change helper() to
void helper(char **a, char* b)
{
*a = malloc(strlen(b) + 1);
memcpy(*a, b, strlen(b) + 1);
printf("%s %s\n", *a, b);
}
which allocates a larger buffer, and copies the content of b - with its contained '\0' into that additional length.
An alternative is to use strcpy() instead of memcpy().
void helper(char **a, char* b)
{
*a = malloc(strlen(b) + 1);
strcpy(*a, b);
printf("%s %s\n", *a, b);
}
The only difference is that strcpy() copies characters until it finds the trailing '\0' in b.
You didnt change a inside the function. when you did malloc a received new address.
void helper(char **a, char *b){
*a = malloc(strlen(b)+1); //+1 for the \0 in the end of b
strcpy(*a, b);
printf("%s %s\n", *a, b);
}
int main(void){
char *b = "hello";
char *a;
helper(&a, b);
printf("%s\n", a);
}
And in you code you didnt use free.. You have to free all the pointers that you did malloc...
so add free(a) in the end of the main.
I renamed variables, to be clear. What #chux said, is value of variable 'a' changed, but value of variable 'x' - not.
void helper(char* a, char* b){
a = malloc(strlen(b));
memcpy(a, b, strlen(b));
printf("%s %s\n", a, b);
}
int main(){
char* y = "hello";
char* x;
helper(x, y);
printf("%s", x);
}
UPD: This is an original code. I just renamed variables in order to disambiguate variables naming, and to do explanations more clear. The problem, as it was pointed by #chux, variable x sent by value, and so cannot be changed in function main.
First mistake I saw is that you have ever to allocate strlen(foo)+1. the correct size for copy a string is this. Than call strcpy() or memset +1 . But with strings I ever use strcpy() on my mind is more performant:
char *strcpy(char *a , const char*b)
{
while(*a++=*b++)
;
return a;
}
then (this is a very trivial version, the real one has more checks)
char * memcpy(a,b,n)
{
while(n--)
*a++=*b++;
return a;
}
there is a counter more to decrease; With memset you have also to call strlen() for get the length, and add one. With strcpy() is not required. So yes, the differences are not appreciable, but there are, but what is appreciable is the redeability, the clearness of the code all this with (teorethical, unless some compiler optimization) better performance
I am trying to have a function take some integer pointers passed from my main() function and assign values to them. However, my program crashes when assigning values. Here is my code:
int computeMoveLocation(int* r, int* c, char* board)
{
//some code up here
*r = 0; //This breaks the program
*c = 0;
}
I'm not trying to change the address of the pointer--I'm trying to change the value of the integer being pointed to. However, I am apparently doing something wrong.
Any help would be greatly appreciated.
EDIT:
Here is the relevant code from main(). Please let me know if I should include anything else as well.
int main()
{
//initialization code
//...
while (1)
{
switch (MACHINE_STATE)
{
case COMPUTER_MOVE :
{
//check rows for three Xs
//check columns for three Xs
//check diagonals for three Xs
//otherwise, move anywhere else
int *r, *c;
computeMoveLocation(r, c, board);
computerMove(*r,*c, board);
PREVIOUS_STATE = COMPUTER_MOVE;
MACHINE_STATE = HUMAN_MOVE;
break;
}
//Other cases
}//end switch
}//end while
}//end main
You are passing in pointers but you didn't allocate memory. So they are pointing at a random location in memory.
int computeMoveLocation(int* r, int* c, char* board) {
//some code up here
*r = 0; //This breaks the program
*c = 0;
}
Bad main :
int main() {
int *r;
int *c;
char *board;
// bad, passing in pointers but didn't allocate memory
computeMoveLocation(r, c, board);
return 0;
}
Good main #1:
int main() {
int r = 5;
int c = 5;
char board = 'a';
// fine, passing address of variables on stack
computeMoveLocation(&r, &c, &board);
return 0;
}
Good main #2:
int main() {
int *r = malloc(sizeof(int));
*r = 5;
int *c = malloc(sizeof(int));
*c = 5;
char *board = malloc(sizeof(char));
*board = 'a';
// fine, passing pointers that point to heap
computeMoveLocation(r, c, board);
free(r);
free(c)
free(board);
return 0;
}
int *r, *c;
computeMoveLocation(r, c, board);
computerMove(*r,*c, board);
You define a pointer but don't make it point to anything. Thus, it is a wild or uninitialized pointer; accessing *r as you do in computeMoveLocation will cause undefined behaviour (in your case, a crash).
You have to either initialize the pointer to point at something known, or just pass the address of an existing int:
int r, c;
computeMoveLocation(&r, &c, ...);
or
static int x, y; // static: only one instance of the variable exists
int *r = &x; // initialize pointers
int *c = &y;
computeMoveLocation(r, c, ...);
or
int *r = malloc(sizeof(int));
int *c = malloc(sizeof(int));
computeMoveLocation(r, c, ...);
In that last case, make sure to free the memory afterwards.
You can always pass a pointer and modify the value that the pointer is pointing to. That is how pointers are supposed to be used. But, you should also be careful to see if the pointer does really points to something or not. The pointer should contain a valid address, the value at whose location you can change. If you don't ensure that, then Undefined Behavior will result.
For Example, when you call your computeMoveLocation function, the address which you are passing should either be of stack or of heap. You can see the code below to understand it.
First possibility
int r, c;
char board;
computeMoveLocation(&r,&c, &board);
Second Possibility
int *r, *c;
char *board;
r = malloc(sizeof(int));
c = malloc(sizeof(int));
board = malloc(sizeof(char));
computeMoveLocation(r,c,board);
Please note that char * is also generally used to pass an address to array of charaters, but, in a such a usage, generally it is ensure that it is null terminated or an accompanying length of the array is also passed.
You can anyway get more details on passing aroung pointers by a simple google search.
EDIT
Now, that you have posted your code which calls computeMoveLocation, you see that you should modify your code according to the Second Possibility shown above, since you are declaring r and c as pointers or you should declare them as integers and call as per the First Possibility shown above. But, you are not doing the same which causes the undefined behavior.
Also, in the above examples, I have allocated memory for board, but, in your case, if it originates at some other place and if it has been handled appropriately there, then it need not be malloced.
#include <stdio.h>
#include <ctype.h>
#define STRING_LEN 500
void stripspaces(char, char, char);
int main(void)
{
char string[STRING_LEN];
char *p1 = string;
char *p2 = string;
printf("Enter a string of up to %d characters:\n", STRING_LEN);
while((*p1++ = getchar()) != '\n') ;
stripspaces(string, *p1, *p2);
getch();
return 0;
}
void stripspaces (char s, char *x1, char *x2){
*x1 = '\0';
x1 = s;
while(*x1 != '\0')
{
if(ispunct(*x1) || isspace(*x1))
{
++x1;
continue;
}
else
*x2++ = *x1++;
}
*x2 = '\0';
printf("\nWith the spaces removed, the string is now:\n%s\n", s);
}
This code is bringing up the following error at the 'stripspaces' function; "passing arg 1 of 'stripspaces' makes integer from pointer without a cast" any help would be excellent.
In case it is not obvious from the code, the program should take in a string and remove all the spaces from it. The function has to remain although I know I can do it without the function.
Your prototype and function definition don't match:
void stripspaces(char, char, char);
vs.
void stripspaces (char s, char *x1, char *x2)
You should change the prototype to
void stripspaces(char, char*, char*);
And in order to make them both work, you should use
void stripspaces(char*, char*, char*);
and
void stripspaces (char *s, char *x1, char *x2)
.
For easier copy & paste, you can use parameter names in the prototype as well.
Both of the answers above are telling you that your function declaration is wrong. Also you are dereferencing pointers when passing them to the function.
stripspaces(string, *p1, *p2);
This turns the call into (char*, char, char) which is not right and will not behave as you expect it to. It is also the source of the particular compiler error you are seeing. The compiler is trying to fit the string(char*) into a char, and thus making an "integer from pointer without cast" since char is basically an 1 byte integer.
Correcting the function declaration would be step one, you want to pass all pointers or you won't be able to manipulate the string.
Fix the declaration and then call the function like this.
stripspaces(string, p1, p2);
You need to change the first argument from char s (single character) to char *s (pointer)
Ok this has been become sooo confusing to me. I just don't know what is wrong with this assignment:
void *pa; void *pb;
char *ptemp; char *ptemp2;
ptemp = (char *)pa;
ptemp2 = (char *)pb;
Can anyone tell me why I'm getting this error:
error: invalid conversion from ‘void*’ to ‘char*’
Actually, there must be something wrong with your compiler(or you haven't told the full story). It is perfectly legal to cast a void* to char*. Furthermore, the conversion is implicit in C (unlike C++), that is, the following should compile as well
char* pChar;
void* pVoid;
pChar = (char*)pVoid; //OK in both C and C++
pChar = pVoid; //OK in C, convertion is implicit
I just tried your code in a module called temp.c. I added a function called f1.
void *pa; void *pb;
char *ptemp; char *ptemp2;
f1()
{
ptemp = (char *)pa;
ptemp2 = (char *)pb;
}
On Linux I entered gcc -c temp.c, and this compiled with no errors or warnings.
On which OS are you trying this?