confused by pointer and local variable in C - c

according to what i learned about function variables they should not 'live' outside their function scope,thus returning a local function variable should cause an error, i do get compiling warnings that i do expect, but it makes no sense to me because the program do work and i am little confused
i wrote the following program:
int * test(int x) {
int f=x+1;
return f; //- int to pointer conversion,idk why this works
}
int main () {
int x = 10;
printf("%d\n",test(x));
}
I first expected the program to crash because we make conversion from int type to pointer at function return, but apparently the program prints 11 which i did not expect, i know this is really bad to write like this anyways it was just a coincidence i wrote something like this and it worked and I had alot of questions after that
the warnings i expected to get :
Solution.c: In function ‘test’:
Solution.c:10:12: warning: return makes pointer from integer without a cast [-Wint-conversion]
return f;
^
Solution.c: In function ‘main’:
Solution.c:15:14: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d\n",test(x));
~^ ~~~~~~~
%ls
can anyone explain how this program works ?

You tell the compiler that function test() should return return a pointer to an integer. You don't. You return a value of an integer.
The compiler says, "You're probably doing unintentional stuff here, just sayin'. I'll cast this integer to a pointer for you."
Then the compiler says, "You want to print the value of an integer here but what you're giving is a pointer. Just sayin'. I'll cast this pointer to an integer for you."

Related

How is the linking done for string functions in C?

I tried to using two different functions from sting.h header file (without including it) strlen() and strtok(). Strlen executed successfully without any error (but some warnings), strtok failed at runtime. Why is it that strlen() function worknig gine but not strtok() if I don't include the header file? I suppose there is something in the linking process that I don't understand. Please clarify for such behavior. However, the program terminates successfully if I print a as '%c' instead of '%s' (strtok returns a garbage value).
CODE:
int main()
{
char string[] = "This is a String";
printf("\nLength of sting is %d\n",strlen(string));
}
WARNINGS:
hello.c: In function ‘main’:
hello.c:4:2: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
hello.c:4:37: warning: incompatible implicit declaration of built-in function ‘strlen’ [enabled by default]
hello.c:4:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
OUTPUT:
$ ./a.out
Length of sting is 16
CODE:
int main()
{
char string[] = "This is a String";
printf("\nLength of sting is %d\n",strlen(string));
char *a = strtok(string," ");
printf("%s",a);
}
WARNINGS:
$ gcc hello.c
hello.c: In function ‘main’:
hello.c:4:2: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
hello.c:4:37: warning: incompatible implicit declaration of built-in function ‘strlen’ [enabled by default]
hello.c:4:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
hello.c:5:12: warning: initialization makes pointer from integer without a cast [enabled by default]
OUTPUT:
$ ./a.out
Length of sting is 16
Segmentation fault (core dumped)
The linking is done implicitly for most of the C standard library. You just have to include the headers of what you use (that's the warnings).
When you don't, your compiler (which is compiling your code as ANSI C) assumes the functions return int, instead of their documented return types. Your program has undefined behavior because of that. Always heed warnings!
You must include the headers string.h and stdio.h.
The first program works because you were lucky enough in that strlen is supposed to return an integer (a size_t to be exact, but it appears on your system the value representation for integers and size_t lets the program slide through).
The second fails because strtok returns a char* but it's assumed an int due to your missing include directives. int and char* are not compatible types, so the "pointer" you get isn't valid.
Sting is a singer, not a C header... Still, the problem is that in C, when you use functions that were not declared, the compiler guesses them to have the types of the arguments you first pass to them and returning an int.
That's the reason why you get all these warnings: several undeclared functions you use don't actually have the deduced signature (although they are not too wrong, and end up working), and the real strtok returns a pointer, not an int (the warning in facts says that you are assigning an int to a pointer without a cast). The crash you are getting most probably comes from the fact that the original pointer is 64 bit, but is truncated to 32 bit when is erroneously considered an int before being assigned to a.
Still, the point to take home is: include headers and don't ever rely on implicit function declaration. It's a dangerous mess that exists only for backward compatibility reasons.

strtoul giving unexpected output

I am trying to use the strtoul function, but as shown below it is returning an unexpected value (adding ff's in the beginning):
#include <stdio.h>
#include <string.h>
#include <limits.h>
main() {
unsigned long temp ;
char *err;
temp = strtoul("3334444444",&err,10);
if (temp > UINT_MAX) {
printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
}else
printf("%lx %x\n",temp,3334444444);
}
$./a.out
ffffffffc6bf959c c6bf959c ffffffff
The above output corresponds to the if part being true, though I expect the else part to get executed here. Can anyone please explain why strtoul is behaving like this? Why does it return ffffffffc6bf959c rather than just c6bf959c? If I use "333444444" (i.e. just one 4 less) rather than "3334444444" in the above code, then I get the correct output (i.e. 13dff55c 13dff55c) corresponding to the else part.
Note : As pointed by melpomene in his reply below, stdlib.h header file should have been included and that will resolve the issue. Can anyone please let me know what is being done by the program by assuming the incorrect return type (int in this case) during compile time which can't be undone (or atleast it is not getting undone in this case) even after knowing the correct return type (unsigned long in this case) during link time ? In short, i want to know how c6bf959c is getting converted to ffffffffc6bf959c because of prototype not provided.
Compiling your code with gcc with warnings enabled gives:
try.c:5:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main() {
^~~~
try.c:5:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
try.c: In function ‘main’:
try.c:8:12: warning: implicit declaration of function ‘strtoul’ [-Wimplicit-function-declaration]
temp = strtoul("3334444444",&err,10);
^~~~~~~
try.c:8:5: warning: nested extern declaration of ‘strtoul’ [-Wnested-externs]
temp = strtoul("3334444444",&err,10);
^~~~
try.c:10:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
^
try.c:12:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
printf("%lx %x\n",temp,3334444444);
^
The main problem is implicit declaration of function ‘strtoul’, indicating that the function is not declared (and thus assumed to return int) because you forgot to #include <stdlib.h>. Adding the missing #include fixes the value of temp.
But you should also have a look at the warnings reported for printf and fix those.

Pointer to a struct accessed using index like an array

#include<stdio.h>
struct test{
int a;
int b;
}m;
int main()
{
m.a=5;m.b=7;
struct test *p;
p = &m;
printf("p[0] = %d\n",*(p+0));
printf("p[1] = %d\n",*(p+1));
return 0;
}
I get the following Ouput:
p[0] = 5
p[1] = 0
Can someone please explain this behavior? Is there a way to print all struct members using index?
Sorry about the typo.
(Updated)
As I could print 1st element using index 0 , though the type of pointer is of "struct test type" and 1st member is an integer , I could get the correct value. Hence, the question triggered about the cause of this behavior. And if all the members can be accessed using the index just like the 1st member was accessed.
In your code,
printf("p[0] = %d\n",*(p+0));
printf("p[0] = %d\n",*(p+1));
invokes undefined behavior as
you are passing wrong type of argument for %d format specifier.
You're accessing out of bound memory by saying *(p+1)
So, the output cannot be explained or justified in any way.
Now, that said, let's analyze the code a bit.
First of all,
p = &a;
is wrong, as there is no variable called a. There is a member variable a for the structure variable m, which can be accessed as m.a. So, you can somehow write
p = (struct test*) &m.a;
Now, using the address of the first element of the structure as the structure address is valid as there is no padding at the beginning of the structure. But that does not mean, you can apply pointer arithmetic directly on the structure pointer p and get each member variable, mainly because
There can be padding between two elements
The pointer p is of type struct test (Though you can get around by casting)
Get a proper compiler. Compiled with default settings on GCC 5, the compilation spits out:
foo.c: In function ‘main’:
foo.c:12:10: error: ‘a’ undeclared (first use in this function)
p = &a;
^
foo.c:12:10: note: each undeclared identifier is reported only once for each function it appears in
foo.c:13:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
printf("p[0] = %d\n",*(p+0));
^
foo.c:14:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
printf("p[0] = %d\n",*(p+1));
^
Perhaps you meant p = &m;.
After that your code invokes undefined behaviour. %d expects that the corresponding argument be an int, yet you provide a struct test. Furthermore on the latter print, the pointer is pointing to uninitialized memory after the m, and garbage is printed. Even the fact that you had 5 printed in the first case cannot be relied on. The C standard does not explain that why or why not this happens, the C standard says "at this time it is ok for the compiler to generate code that prints 42342, crash the program, or do whatever else, and it is fine by this standar d."
In C compilers the warnings usually mean "standard violations" in which case undefined behaviour is probable. A newcomer to C programming language should always consider all compiler warnings especially with default settings as being fatal errors.
I compiled your code with gcc and i got.
In function ‘main’:
error: ‘a’ undeclared (first use in this function)
p = &a;
^
note: each undeclared identifier is reported only once for each function it appears in
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
printf("p[0] = %d\n",*(p+0));
^
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
printf("p[0] = %d\n",*(p+1));
Assuming you meant p=&m, here is my explanation
printf("p[0] = %d\n",*(p+0));
printf("p[0] = %d\n",*(p+1));
First analyse whether deferring pointer like you did in printf function is correct or not.
The *(p+0) will give you the access to the struct test variabe m. As, you have assigned the address of a variable of type struct test to the pointer p, deferring pointer *p or *(p+0) will give you the access to the variable m. But the address assigned to the pointer is of a single variable not of the array of type struct test, deferring (p+1) will give you UNDEFINED BEHAVIOR. For example, *(p+1) would have worked if (not in printf statement)
struct test m[20];
struct test *p;
(*(p+0)).a=2;
(*(p+1)).a=5;
Is there a way to print all struct members using index?
You can. But there is no overloading of operators in c. So, you can achieve this by -
printf("a=%d, b=%d", p->a, p->b);
If pointer p points to array of type struct test, then you can use index in printf as
printf("a=%d, b=%d of %dth element", p[i].a, p[i].b, i);
My suggestion for your future code experimentation will be first analyse warning and error given by your code. The warnings can help to rectify most of the bugs in your code. I always compile my c/c++ code with gcc/g++ compiler and use flags like -Wall, -Wshadow, -Wextra. You can google a warning if you don't understand it.
You are assigning the address of a to p directly. a is a member of m and so cannot be accessed directly. And as of your code, you should use an integer pointer for your arithmetic.
you need to modify a part of your code
struct test *p;
p = &a;
to
int *p;
p = &m.a;
now the code should work as you desire.
First, you have a typo in your code.
Please correct it from p = &a; to p = &m;, so that the error complained by the compiler shall be removed.
Second, I guess you expect the output to be p[0] = 5 and p[1] = 7.
To achieve that, modify your code from
printf("p[0] = %d\n",*(p+0));
printf("p[1] = %d\n",*(p+1));
to
printf("p[0] = %d\n",p->a);
printf("p[1] = %d\n",p->b);
can work.

Warnings in a very basic Pointer Program in C

I've just started with pointers in c. This program gives the desired output but I am getting the below warnings when I compile it, What am I doing wrong?
pointer.c:3: warning: initialization makes pointer from integer without a cast
pointer.c:5: warning: incompatible implicit declaration of built-in function ‘printf’
pointer.c:8: warning: assignment from incompatible pointer type
pointer.c:12: warning: assignment makes pointer from integer without a cast
And my code is:
int main (int argc, char *argv[])
{
int *x=2, *ampx, *starampx, starx;
printf("x=");
printf("%d\n",x);
ampx=&x;
printf("&x=");
printf("%d\n",&x);
starampx=*ampx;
printf("*&x=");
printf("%d\n",starampx);
return 0;
}
Here is why:
initialization makes pointer from integer without a cast - int *x = 2, ... should be int x = 2, ...
incompatible implicit declaration of built-in function ‘printf’ - You need to add an #include <stdio.h> line at the top
assignment from incompatible pointer type - This will be fixed by the #1 change
assignment makes pointer from integer without a cast - *starampx should be starampx in the declaration.
In addition, printing pointers should be done with %p specifier, not %d:
printf("%p\n",&x);
Here is your fixed program on ideone: link.
int *x=2
is actually causing your program to have undefined behavior. It tells the compiler to point at an address 2, which may or may not be valid and derferencing the pointer will causes an undefined behavior.
Whenever you are using pointers, You need to make the pointer point to a valid memory big enough to store a int before you can store anything. So you either need:
int i = 2;
int *x = &i;
or you simply use:
int x = 2;
Considering, how you use x later in the program the latter is what you need.
You need to include stdio.h which tells the compiler that printf is an standard c library function.
In your code, in this statement, you have a problem.
int *x=2, *ampx, *starampx, starx;
^ ^
| |
*x is a pointer. To store the value of 2, you would need to allocate space for the same. Instead of the current implementation, please try with
int x=2, *ampx, starampx, starx;

Isn't const supposed to be constant?

Check out this code
#include<stdio.h>
int main()
{
const int a=7;
int *p=&a;
(*p)++;
printf("*p=%d\np=%u\na=%d\n&a%u",*p,p,a,&a);
getch();
}
The output you get for this is
*p=8
p=1245064
a=8
&a1245064
How is this possible?? We declared variable a as constant. Doesnt this mean that the location pointed to by a can never be changed during the course of pgm execution??
That's undefined behavior - in your case it is working as you described, but it could just as well crash the program or cause any other problems. In your case const doesn't prevent the compiler from allocating the variable in modifiable memory, so you technically can modify it by obtaining a pointer to that variable and working through the pointer.
Undefined behaviour is not to be relied upon ;-)
Would you really want to use C if it actually prevented that from working? The fact it works that way is very much in the spirit of the language.
Reading your comment "it only gives a warning saying suspicious pointer conversion" it should be clear enough to deduce that you are doing something illegal.
You are assigning to a int * variable a const int * value.
The fact that C hasn't any runtime checkings to prevent you from modifying that memory address doesn't imply that it's allowed! (and in fact, the static type system checking is telling you that).
If yours doesn't detect this automatically, just get yourself a decent compiler. E.g clang gives me 4 problems with your code:
clang -c -o test-const.o test-const.c
test-const.c:17:7: warning: initializing 'int const *' discards qualifiers, expected 'int *' [-pedantic]
int *p=&a;
^ ~~
test-const.c:19:20: warning: conversion specifies type 'unsigned int' but the argument has type 'int *' [-Wformat]
printf("*p=%d\np=%u\na=%d\n&a%u",*p,p,a,&a);
~^ ~
test-const.c:19:32: warning: conversion specifies type 'unsigned int' but the argument has type 'int const *' [-Wformat]
printf("*p=%d\np=%u\na=%d\n&a%u",*p,p,a,&a);
~^ ~~
test-const.c:20:2: warning: implicit declaration of function 'getch' is invalid in C99 [-Wimplicit-function-declaration]
getch();
^
4 diagnostics generated.
These are all serious problems.

Resources