C program: Changing the string in a function by using double pointer - c

#include<stdio.h>
#include<string.h>
void fun(char** a)
{
strcpy(*a, "ponky" );
}
int main()
{
char a[100] = "pinky";
fun(&a );
printf("\n %s \n", a );
return 0;
}
Copying a string in a function through double pointer.
Why the above program gives segmentation fault?

note: I suspect this question to be a duplicate and I've found many similar questions but I haven't found an exact duplicate. Therefore I post an answer. Should someone find an exact duplicate I'll remove this answer.
Why the above program gives segmentation fault?
The short answer is that you have a type mismatch when calling fun. You don't give fun a "pointer to pointer to char" as it expects. Consequently, it fails big time.
But what do you then pass to fun? And how should you have found out that something was wrong?
The answer is: Set compiler warning level high and consider all warnings to be errors
For gcc that could be:
gcc -xc -Wall -pedantic -Werror main.c
(Other compilers have similar options)
On my system I get:
In function 'main':
error: passing argument 1 of 'fun' from incompatible pointer type [-Werror=incompatible-pointer-types]
13 | fun(&a );
| ^~
| |
| char (*)[100]
note: expected 'char **' but argument is of type 'char (*)[100]'
3 | void fun(char** a)
| ~~~~~~~^
so it's clear that something is wrong and the following line tells it all:
note: expected 'char **' but argument is of type 'char (*)[100]'
you pass char (*)[100] instead of char **
But what is char (*)[100]?
It's a "pointer to an array of char". Since fun uses it as "pointer to pointer to char" you have undefined behavior (which in your case resulted in a seg fault). That is - fun would expect *a to be a "pointer to char" but you passed "pointer to an array of char" so *a is not a "pointer to char".
It's undefined behavior so we can't tell what is going on. However, on many systems it will read the string "pinky" and interpretate it as a pointer to char which will fail big time.

Related

C: incompatible pointer types passing 'char (*)' to parameter of type 'char (*)[5]', but program works fine

I am getting the following warning:
warning: incompatible pointer types passing 'char ()' to parameter of type 'char ()[5]' [-Wincompatible-pointer-types]
printField(field[5]);
The printField function looks like this:
void printField(char (*field)[5])
{
...
}
and the field I am giving to it is defined as follows:
char (*field) = get_field(input);
Here is the function call:
printField(field);
Now, I do understand, that there is obviously some sort of mismatch happening, but I can't tell what to change for it not to be there anymore. I would appreciate it very much, if someone could help me.
Assuming that get_field return a pointer to the first element (character) of an array (null-terminated string), then that happens to be the same as the pointer to the array itself.
If we illustrate it with a simple array:
char s[5];
Then that will look something like this in memory (with pointers added):
+------+------+------+------+------+
| s[0] | s[1] | s[2] | s[3] | s[4] |
+------+------+------+------+------+
^
|
&s[0]
|
&s
Now as can be seen that there are two pointers pointing to the same location: &a[0] and &s.
&s[0] is what using the array decay to, and it's the type char *.
&s is a pointer to the array itself, and have the type char (*)[5].
When we apply it to your case, field is the first pointer, it points to the first element of an array. Which happens to be the same location as the pointer to the array itself which is what printField expects.
That's the reason it "works". But you should not do like that, you should fix the function to take an char * argument instead:
void printField(char *field);
The types are different.
char *ptr; declares the pointer to char
char (*ptr)[5]; declared the pointer to an array of 5 characters.
Those pointer types are not compatible - thus compiler warning.
In your case, both pointers refer to the same place in the memory (and that is the reason why the program works).

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."

Why 'c[&i]' compiles while 'c[i]' doesn't? [duplicate]

This question already has answers here:
With arrays, why is it the case that a[5] == 5[a]?
(20 answers)
String as an array index
(3 answers)
Closed 6 years ago.
This example compiles without warnings/errors (gcc 4.8.2 -Wall):
#include <stdio.h>
int main()
{
char c;
int i;
printf("%p %02x\n",&i,c[&i]);
printf("%p %02x\n",&c,c[&c]);
// important to note that this line DOESN'T compile:
//printf("%p %02x\n",&i,c[i]);
// which makes sense as c is NOT an array, it is a char.
return 1;
}
Why does the syntax c[&i] compile ? Is it intentional or an accident?
Is the syntax c[&i] semantically valid ? (Does it have any useful meaning?)
Example of output for me: (pointers change each time)
0xbfb2577c b7718cea
0xbfb2577b 08
This question originated from a strange bit of code 'ch2[&i]' in question here:
C duplicate character,character by character
NOTE#0 (updated, upon reflection) on duplicates/similar questions:
This question is not a duplicate of the linked questions on c array references. It is related so it is useful to refer to them. The related questions discuss the valid a[b] and b[a] case where one of a or b is a pointer and the other is an int. This question deals with the more weird and maybe should be invalid case where one of a or b is a char.
With C arrays, why is it the case that a[5] == 5[a]? 14 answers
With arrays, why is it the case that a[5] == 5[a]?
String as an array index 3 answers
String as an array index
NOTE #1: This happens with compiler as the type of variable c is char and that can be used as index into array when combined with pointer.
NOTE #2: for some reason, type of c[<ptr>] evaluates to type of <ptr>.
E.g.: the resulting types of c[&pi] and c[&pc] cause warnings in the following code:
int *pi; char *pc; pi=&i; pc=&c;
printf("%p %02x\n",&pi,c[&pi]);
printf("%p %02x\n",&pc,c[&pc]);
Warnings on type 'int *' or 'char *' instead of 'unsigned int':
c/so_cweirdchar2.c: In function ‘main’:
c/so_cweirdchar2.c:13:5: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int *’ [-Wformat=]
printf("pi %p %02x\n",&pi,c[&pi]);
^
c/so_cweirdchar2.c:14:5: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘char *’ [-Wformat=]
printf("pc %p %02x\n",&pc,c[&pc]);
^
In C, the [] postfix pointer displacing operator is commutative. If a[i] is a valid expression, then so is i[a] and means the same thing. Though we have to watch operator associativity and precedence to make sure we do this reversal right. Your c[&i] means the same thing as (&i)[c]: the pointer &i displaced by the integer c.
The basis for the commutativity of [] is the equivalence between indexing and the combination of pointer displacement and dereferencing, where the + operator is commutative:
E1[E2] <--> *(E1 + E2)
^ ^
| |
v v
E2[E1] <--> *(E2 + E1)
Here we understand E1 to be fully parenthesized expressions, so we are unconcerned about precedence. In effect we are manipulating abstract syntax trees in which E1 and E2 are nodes.
Compiles with no error. Perfectly valid C:
int main (int argc, char** argv)
{
int n=5;
char *a="abcdefghijk";
printf("%c\n", a[n]);
printf("%c\n", n[a]);
return 0;
}

Getting warning when using `addres of` operator with array as an initializer to a pointer

I am learning C and I am having some troubles to truly understand arrays and pointers in C, after a lot of research (reading the K&R book (still reading it), reading some articles and some answers here on SO) and taking tons of notes along the way, I've decided to make a little test / program to prove my understanding and to clear some doubts, but I'm yet confused by the warning I am getting using this code:
#include <stdio.h>
int main(int argc, char **argv) {
char a[3] = {1, 2, 3};
char *p = &a;
printf("%p\n", a); /* Memory address of the first element of the array */
printf("%p\n", &a); /* Memory address of the first element of the array */
printf("%d\n", *a); /* 1 */
}
Output compiling with GNU GCC v4.8.3:
warning: initialization from incompatible pointer type
char *p = &a;
^
0x7fffe526d090
0x7fffe526d090
1
Output compiling with VC++:
warning C4047: 'initializing' : 'char *' differs in levels of indirection from 'char (*)[3]'
00000000002EFBE0
00000000002EFBE0
1
Why am I getting this warning if &a and a are supposed to have the same value and compiling without warnings when using just a as an initializer for p?
&a is the memory address of the entire array. It has the same value as the address of the first element (since the whole array starts with the first element), but its type is a "pointer to array" and not "pointer to element". Hence the warning.
You are trying to initialize a char* with a pointer to a char[3], which means a char(*)[3].
Unsurprisingly, the compiler complains about the mismatch.
What you wanted to do is take advantage of array-decay (an array-name decays in most contexts to a pointer to its first element):
char* p = a;
As an aside, %p is only for void*, though that mismatch, despite being officially Undefined Behavior, is probably harmless.

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