How is the linking done for string functions in C? - 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.

Related

confused by pointer and local variable in 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."

C : warning: assignment makes pointer from integer without a cast [enabled by default]

This is my code
#include<stdio.h>
#include<stdlib.h>
void main() {
FILE *fp;
char * word;
char line[255];
fp=fopen("input.txt","r");
while(fgets(line,255,fp)){
word=strtok(line," ");
while(word){
printf("%s",word);
word=strtok(NULL," ");
}
}
}
This the warning I get.
token.c:10:7: warning: assignment makes pointer from integer without a cast [enabled by default]
word=strtok(line," ");
^
token.c:13:8: warning: assignment makes pointer from integer without a cast [enabled by default]
word=strtok(NULL," ");
^
The word is declared as char*. Then why this warning arises?
Include #include <string.h> to get the prototype for strtok().
Your compiler (like in pre-C99 C) assumed strtok() returns an int because of that. But not providing function declaration/prototype is not valid in modern C (since C99).
There used an old rule in C which allowed implicit function declarations. But implicit int rule has been removed from C language since C99.
See: C function calls: Understanding the "implicit int" rule
strtok() is prototyped in <string.h>, you need to include it.
Otherwise, with the lack of forward declaration, your compiler assumes that any function used for which the signature is not known to it, returns an int and accepts any number of parameters. This was called implicit declarration .
FWIW, implicit function declaration is now invalid as per the latest standard. Quoting C11, Foreward, "Major changes in the second edition included:"
remove implicit function declaration
You need to include string.h
#include <string.h>

Error in C: [assignment makes pointer from integer without a cast [enabled by default]]

I`ve this function in C, ISO C90
char **read_words(char *file_name);
But when I use it
char **words;
...
words = read_words("file.txt");
...
I've this problem
main.c:72:14: warning: assignment makes pointer from integer without a cast [enabled by default]
words=read_words("file.txt");
^
When I debugg to see what is the problem, the function returns the adress 0x60003bbe0 but the variable 'words' takes the value 0x3bbe0, and I`ve have no idea what's the problem

Is there anything that i missed in signed number in C language?

This is my basic C test program.
After I built it, I just entered negative number like -1, -2, etc. in console.
But the result is "oh", not "another number".
I don't know why this happens, because negative numbers should make the 'if' statement true.
int main(int argc, char* argv[]){
long int num;
scanf("%d", &num);
if(num ==1 || num < 0){
printf("another number\n");
}else{
printf("oh\n");
}
}
When you use the %d format string with scanf, the corresponding argument will be treated as int*. But you have passed a long int*. The value scanf stores will not be the same size as what your if statement reads.
Formally, you get undefined behavior. In practice, on most platforms scanf will write only part of the variable, and the rest will be left with an arbitrary value, with the usual bad effects on future use.
Use %ld for long variables, %d for ints. Change your code to one of these:
int num;
scanf("%d", &num);
or
long int num;
scanf("%ld", &num);
/tmp$ gcc -Wall foo.c
foo.c: In function ‘main’:
foo.c:4:5: warning: implicit declaration of function ‘scanf’ [-Wimplicit-function-declaration]
foo.c:4:5: warning: incompatible implicit declaration of built-in function ‘scanf’ [enabled by default]
foo.c:4:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘long int *’ [-Wformat]
foo.c:7:9: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
foo.c:7:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
foo.c:9:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
foo.c:11:1: warning: control reaches end of non-void function [-Wreturn-type]
fix the causes of those warnings and all the bugs will go away.

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