Warning in C: assignment makes integer from pointer without a cast - c

I keep getting this error when compiling my program. This is just a small part of my code, so if needed I will provide the rest of the code. Any ideas on why this is occuring?
void strip_quotes(char s[]) {
if (s[0]=='"') s=s+1;
if (s[strlen(s)-2]=='"') s[strlen(s)-2]=NULL;
}

You are setting a character of s to NULL. The proper way to add a null character to a string is to use '\0'.
To explain the message, NULL is likely defined as (void*)0, so when you assign it, you are converting void* to char, hence the warning.

As Dave has already correctly pointed out the reason for the compiler error:
s[strlen(s)-2]=NULL; /* = (void*)0 */
There is another bug in the code that won't cause a compiler error:
if (s[0]=='"') s=s+1;
the increment of s will not be visible to the caller, as C passes by value including pointers (see http://c-faq.com/ptrs/passptrinit.html). Options for correcting:
shift the content of the array to the left using memmove() (or some other copy mechanism)
pass the address of the pointer (a char**)
return a pointer to s
Changing the content of s is preferable as it avoids a possible problem if the array was dynamically allocated: only pointers returned by malloc() (or calloc() and realloc()) can be passed to free(). If the value of s is changed then it cannot be free()d via s.
Note that:
void strip_quotes(char s[]) {
is equivalent:
void strip_quotes(char* s) {
incase you were confused as to were pointers are used in the code.

Dave got it, but I'll try to add a bit.
NULL is a pointer of type void*, which can be assigned to any pointer type. If you are setting a pointer to a value that can never be used to represent valid memory, use NULL.
'\0', aka NUL, is ascii value 0 and is used to terminate strings. It is of type char. http://www.december.com/html/spec/ascii.html .

void strip_quotes(char s[]) {
int len = strlen(s);
if(s[len-1] == '"')
s[--len] = '\0';
if(s[0]=='"')
memmove(s, s+1, len);
}

Related

Why we didn't use * during dereferencing the pointer?

In the below code, we get a pointer from strdup(source) and we store it in a pointer named target.
Now, when we print the string using pointer, we don't add * at the beginning of the pointer: why is it so? As I studied whenever we want to dereference any pointer we use *pointer_name. If we add * in the below code, we get an error.
I am very beginner, so pls ans in easy words.
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "Programming";
char* target = strdup(source);
printf("%s\n",target);
return 0;
}
printf expects a char pointer in the place of the %s specifier.
https://en.cppreference.com/w/c/io/fprintf
char* target = strdup(source);
printf("%s\n",target);
Why we don't use *target in the code above?
The explanation is quite simple, as already stated in previous answers: target has type char pointer, which is exactly what printf() wants in the above call.
Now, printf() is a little complicated because its semantic is not simple - basically it accepts zero or more arguments after the first, of any type (possibly applying promotion). But if we use strdup() again, maybe it is simpler:
char* target2 = strdup(target);
Here, if you wrote strdup(*target), the compiler might warn that you are passing a char instead of a pointer to char.
strdup() returns a char*, hence the char* type of target. target holds a pointer to the first character in an array of chars. printf("%s", string) expects string to be a char*, so there’s no reason to do anything to target; just pass it to printf().
If you dereferenced target, you would get a single char (P in this case). printf() would then complain that you had supplied a character instead of a string (pointer to character). Even worse, the program could compile, and then printf() would try to print the string at address P (0x50), which would result in probably unwanted behaviour.
When working with arrays—a string is a type of array—you rarely want to dereference the array.

How to point at incompatible pointer type in C?

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.

Segmentation fault while implementing reverse function in C

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);
}

NULL implementation and pointer assignment

I have a couple of questions that came up when I was reading and writing code..
I already get another approach, but this questions still in my mind and I didn't find any good answer, so let's see:
Can I assign a pointer to a variable in a portable way, even losing
information? See the situation, I have a function that could return
NULL if an error, or a char, supposing that NULL is all 0, the char
will be nul, is this correct?
void * function_returning_null_or_char ();
An int variable is suppose to hold a pointer? (I read it in somewhere)..
My implementation of NULL is #define NULL (void *) 0. Would be better if it was #define NULL 0? So
it could be assigned to variable and pointers, like a char or an int
*. (see question 1)
When I assign a pointer to NULL, when I cast it to short or char
or another type, the value will be 0? Or The value will be the
special value of NULL cutted to fit on that type?
I think that all questions are resumed in:
The compiler is smart enough to convert a NULL pointer in 0s when it is cast to a variable?
example code:
int *p = NULL;
char c = (char) p; // This works, I dont know why, and char is equal to '/0';
char c = NULL; //This works because the compiler is smart to convert NULL to '/0' event stddef.h defining NULL as (void *)0;
char c = (char) function_returning_null_or_char (); //if this function return NULL whats the value of c? If NULL have a special value, c will have a special value too, or it will be 0?
It doesn't make sense to have a function that can return either NULL (a pointer value) or a char value. There is a null character '\0', but it's not related to the null pointer. There are various ways you can have a function return either a char value or some indication that there is no valid value. For example, return a structure.
No, an int variable is not supposed to hold a pointer. An int variable holds an integer value; to hold a pointer, use a pointer variable. (You can convert between integer and pointer types, but doing so makes sense far less often than you might think.)
NULL is defined for you by the implementation, in <stddef.h> and several other standard headers. Do not try to redefine it yourself.
Converting a null pointer value to an integer type yields an implementation-defined value. If you care what that value is, you're probably doing something wrong.
Pointers are not integers; don't try to treat them as integers. The representation of a null pointer is implementation-defined; it's commonly all-bits-zero, but there's no guarantee of that.
Take a look at the comp.lang.c FAQ, particularly sections 4 (Pointers) and 5 (Null Pointers).

memcpy fails but assignment doesn't on character pointers

Actually, memcpy works just fine when I use pointers to characters, but stops working when I use pointers to pointers to characters.
Can somebody please help me understand why memcpy fails here, or better yet, how I could have figured it out myself. I am finding it very difficult to understand the problems arising in my c/c++ code.
char *pc = "abcd";
char **ppc = &pc;
char **ppc2 = &pc;
setStaticAndDynamicPointers(ppc, ppc2);
char c;
c = (*ppc)[1];
assert(c == 'b'); // assertion doesn't fail.
memcpy(&c,&(*ppc[1]),1);
if(c!='b')
puts("memcpy didn't work."); // this gets printed out.
c = (*ppc2)[3];
assert(c=='d'); // assertion doesn't fail.
memcpy(&c, &(*ppc2[3]), 1);
if(c != 'd')
puts("memcpy didn't work again.");
memcpy(&c, pc, 1);
assert(c == 'a'); // assertion doesn't fail, even though used memcpy
void setStaticAndDynamicPointers(char **charIn, char **charIn2)
{
// sets the first arg to a pointer to static memory.
// sets the second arg to a pointer to dynamic memory.
char stat[5];
memcpy(stat, "abcd", 5);
*charIn = stat;
char *dyn = new char[5];
memcpy(dyn, "abcd", 5);
*charIn2 = dyn;
}
your comment implies that char stat[5] should be static, but it isn't. As a result charIn points to a block that is allocated on the stack, and when you return from the function, it is out of scope. Did you mean static char stat[5]?
char stat[5];
is a stack variable which goes out of scope, it's not // sets the first arg to a pointer to static memory.. You need to malloc/new some memory that gets the abcd put into it. Like you do for charIn2
Just like what Preet said, I don't think the problem is with memcpy. In your function "setStaticAndDynamicPointers", you are setting a pointer to an automatic variable created on the stack of that function call. By the time the function exits, the memory pointed to by "stat" variable will no longer exist. As a result, the first argument **charIn will point to something that's non-existent. Perhaps you can read in greater detail about stack frame (or activation record) here: link text
You have effectively created a dangling pointer to a stack variable in that code. If you want to test copying values into a stack var, make sure it's created in the caller function, not within the called function.
In addition to the definition of 'stat', the main problem in my eyes is that *ppc[3] is not the same as (*ppc)[3]. What you want is the latter (the fourth character from the string pointed to by ppc), but in your memcpy()s you use the former, the first character of the fourth string in the "string array" ppc (obviously ppc is not an array of char*, but you force the compiler to treat it as such).
When debugging such problems, I usually find it helpful to print the memory addresses and contents involved.
Note that the parenthesis in the expressions in your assignment statements are in different locations from the parenthesis in the memcpy expressions. So its not too suprising that they do different things.
When dealing with pointers, you have to keep the following two points firmly in the front of your mind:
#1 The pointer itself is separate from the data it points to. The pointer is just a number. The number tells us where, in memory, we can find the beginning of some other chunk of data. A pointer can be used to access the data it points to, but we can also manipulate the value of the pointer itself. When we increase (or decrease) the value of the pointer itself, we are moving the "destination" of the pointer forward (or backward) from the spot it originally pointed to. This brings us to the second point...
#2 Every pointer variable has a type that indicates what kind of data is being pointed to. A char * points to a char; a int * points to an int; and so on. A pointer can even point to another pointer (char **). The type is important, because when the compiler applies arithmetic operations to a pointer value, it automatically accounts for the size of the data type being pointed to. This allows us to deal with arrays using simple pointer arithmetic:
int *ip = {1,2,3,4};
assert( *ip == 1 ); // true
ip += 2; // adds 4-bytes to the original value of ip
// (2*sizeof(int)) => (2*2) => (4 bytes)
assert(*ip == 3); // true
This works because the array is just a list of identical elements (in this case ints), laid out sequentially in a single contiguous block of memory. The pointer starts out pointing to the first element in the array. Pointer arithmetic then allows us to advance the pointer through the array, element-by-element. This works for pointers of any type (except arithmetic is not allowed on void *).
In fact, this is exactly how the compiler translates the use of the array indexer operator []. It is literally shorthand for a pointer addition with a dereference operator.
assert( ip[2] == *(ip+2) ); // true
So, How is all this related to your question?
Here's your setup...
char *pc = "abcd";
char **ppc = &pc;
char **ppc2 = &pc;
for now, I've simplified by removing the call to setStaticAndDynamicPointers. (There's a problem in that function too—so please see #Nim's answer, and my comment there, for additional details about the function).
char c;
c = (*ppc)[1];
assert(c == 'b'); // assertion doesn't fail.
This works, because (*ppc) says "give me whatever ppc points to". That's the equivalent of, ppc[0]. It's all perfectly valid.
memcpy(&c,&(*ppc[1]),1);
if(c!='b')
puts("memcpy didn't work."); // this gets printed out.
The problematic part —as others have pointed out— is &(*ppc[1]), which taken literally means "give me a pointer to whatever ppc[1] points to."
First of all, let's simplify... operator precedence says that: &(*ppc[1]) is the same as &*ppc[1]. Then & and * are inverses and cancel each other out. So &(*ppc[1]) simplifies to ppc[1].
Now, given the above discussion, we're now equipped to understand why this doesn't work: In short, we're treating ppc as though it points to an array of pointers, when in fact it only points to a single pointer.
When the compiler encounters ppc[1], it applies the pointer arithmetic described above, and comes up with a pointer to the memory that immediately follows the variable pc -- whatever that memory may contain. (The behavior here is always undefined).
So the problem isn't with memcopy() at all. Your call to memcpy(&c,&(*ppc[1]),1) is dutifully copying 1-byte (as requested) from the memory that's pointed to by the bogus pointer ppc[1], and writing it into the character variable c.
As others have pointed out, you can fix this by moving your parenthesis around:
memcpy(&c,&((*ppc)[1]),1)
I hope the explanation was helpful. Good luck!
Although the previous answers raise valid points, I think the other thing you need to look at is your operator precedence rules when you memcpy:
memcpy(&c, &(*ppc2[3]), 1);
What happens here? It might not be what you're intending. The array notation takes higher precedence than the dereference operator, so you first attempt perform pointer arithmetic equivalent to ppc2++. You then dereference that value and pass the address into memcpy. This is not the same as (*ppc2)[1]. The result on my machine is an access violation error (XP/VS2005), but in general this is undefined behaviour. However, if you dereference the same way you did previously:
memcpy(&c, &((*ppc2)[3]), 1);
Then that access violation goes away and I get proper results.

Resources