The output of this program is:
XBCDO
HELLE
Can someone explain why this is so?
#include<stdio.h>
void swap(char **p, char **q) {
char *temp = *p;
*p = *q;
*q = temp;
}
int main() {
int i = 10;
char a[10] = "HELLO";
char b[10] = "XBCDE";
swap(&a, &b);
printf("%s %s", a, b);
}
You are confused about the difference between pointers and arrays. (It is a confusing part of the language.) swap expects pointers to pointers, but you have given it pointers to arrays. This is such a serious mistake that GCC warns about it even if you don't turn on any warnings (it ought to issue hard errors, but some very, very old code does stuff like this intentionally and they don't want to break that).
$ gcc test.c
test.c: In function ‘main’:
test.c:16:10: warning: passing argument 1 of ‘swap’ from incompatible pointer type [-Wincompatible-pointer-types]
swap(&a, &b);
^
test.c:3:1: note: expected ‘char **’ but argument is of type ‘char (*)[10]’
swap(char **p, char **q)
^~~~
test.c:16:14: warning: passing argument 2 of ‘swap’ from incompatible pointer type [-Wincompatible-pointer-types]
swap(&a, &b);
^
test.c:3:1: note: expected ‘char **’ but argument is of type ‘char (*)[10]’
swap(char **p, char **q)
^~~~
The mistake causes the program to have undefined behavior - it doesn't have to do anything that makes any sense at all.
The program you probably were trying to write looks like this:
#include <stdio.h>
static void swap(char **p, char **q)
{
char *temp = *p;
*p = *q;
*q = temp;
}
int main(void)
{
char a[10] = "HELLO";
char b[10] = "XBCDE";
char *c = a;
char *d = b;
swap(&c, &d);
printf("%s %s", c, d);
}
The output of this program is XBCDE HELLO, which I think is what you were expecting. c and d are actually pointers, and they are set to point to the first elements of the arrays a and b; swap works as expected when applied to c and d.
If it doesn't make any sense that c and d are different from a and b, you need to get your hands on a good C textbook and you need to read the chapter on pointers and do all the exercises. (If it doesn't have at least one entire chapter on pointers, with exercises, it's not a good C textbook.)
Related
#include <stdio.h>
int main()
{
char grade = 'A';
int *p = &grade;
printf("The address where the grade is stored: %p\n", p);
printf("Grade: %c\n", grade);
return 0;
}
I get this error each time I compile the code on VScode but never on code blocks.
warning: incompatible pointer types initializing 'int *' with an
expression of type 'char *' [-Wincompatible-pointer-types]
int *p = &grade;
^ ~~~~~~
1 warning generated.
./main
The address where the grade is stored: 0x7ffc3bb0ee2b
Grade: A"
The warning tells you exactly what it is. It says:
incompatible pointer types initializing 'int *' with an expression of type 'char *'
This means that p is of type int *, that &grade is of type char *, and that these two pointers are not compatible. The solution is to change the declaration of p to:
char *p = &grade;
One more thing. Usually you can safely do implicit conversions to and from any pointer to void *, but not when passed as argument to a variadic function. If you want to print the address, use this:
printf("%p", (void *)p);
But only cast when needed. Never do it just to get rid of warnings. Here is an answer I wrote about that: https://stackoverflow.com/a/62563330/6699433
As an alternative, you could use a void pointer directly:
void *p = &grade;
printf("%p", p);
But then you would need to cast if you want to dereference it. For example:
char c = *(char*)p;
That cast is not necessary if p is declared as char *.
I did a function f which takes as input a (void*), convert it to a (int*) and print the value.
#include <stdlib.h>
#include <stdio.h>
void f(void* p)
{
int *pi = (int*)p;
printf("%d\n", *pi);
}
int main()
{
int x = 1;
int *px = &x;
void *pv = (void*)px;
f(pv);
return 0;
}
Is it possible to implement a function:
void f2(void** pp);
such that it performs the "same" operations of the function f? My goal is to learn how to convert a (int*) to a (void**) and viceversa.
EDIT: error and warning of #tadman code (I did a mistake)
fvv.c: In function ‘f2’:
fvv.c:10:12: warning: initialization of ‘int *’ from incompatible pointer type ‘int **’ [-Wincompatible-pointer-types]
10 | int *pi = (int**)p;
| ^
fvv.c:12:17: error: invalid type argument of unary ‘*’ (have ‘int’)
12 | printf("%d\n", **pi);
|
EDIT2
fvv.c: In function ‘main’:
fvv.c:19:5: warning: passing argument 1 of ‘f2’ from incompatible pointer type [-Wincompatible-pointer-types]
19 | f2(&px);
| ^~~
| |
| int **
fvv.c:7:16: note: expected ‘void **’ but argument is of type ‘int **’
7 | void f2(void** p)
You can take any level of indirection you want, up to the blatantly, utterly absurd (void*******), but I'm not sure why this would be useful:
void f2(void** p)
{
// Note you must maintain the same level of indirection
int **pi = (int**)p;
// Since this is a ** pointer, it requires ** to fully de-reference
printf("%d\n", **pi);
}
To call this you need a pointer to a pointer:
int x = 1;
int *px = &x;
f2((void**) &px);
In C terms a pointer to a pointer is often interpreted to mean one of the two following things:
A two dimensional array
A mutable pointer argument
Neither of those apply here.
That being said, in C there's not a lot of rules as to what you can and can't convert. If you want to do it, C isn't going to get in your way, even if the resulting code makes no sense or will crash immediately when executed.
You can convert int* to void** and back again, C won't care, but you should have a really good reason for doing such a thing. Normally arbitrary pointers are almost always specified as void*, and as this can be recast into whatever you want, it's sufficient.
For example, you can specify void* as an argument when that pointer is actually int**, something you'll see quite often, as in thread_create taking a void* arg argument. That's not limited to mere pointers, you can cast to your heart's content.
To understand more precisely, see the below explanation.
int arr[3];
Now, write a declaration in such a way, xyz = &arr; where compiler should not throw warning.
How to declare xyz?
For the below code,
int main(void)
{
int arr[3];
int *p;
int **pp;
p = arr;
pp = &arr;
return 0;
}
.
WARNING:
t.c: In function ‘main’:
t.c:11:4: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
pp = &arr;
^
Goal: Need a declaration such that xyz = &arr, where it should not throw warning.
int (*xyz)[3]
Pointer to an array of 3 int elements.
And FYI int** and int (*)[3] is not same.
My code needs to pass an array to a void pointer (The struct has (void *) that cannot be modified). The two versions of code below produce the same output but the latter has two warnings. My question is which of the two methods is preferred? Is there a way to typecast to remove the warnings?
This version does not have warnings and produces the output as expected:
#include <stdio.h>
void test(void *var_arr, char var_1);
typedef struct {
char chip;
void *buffer;
}test_struct;
int main()
{
int test_array[3] = {3,7,5};
char var_1 = 0x20;
printf("Hello, World!\n");
test(&test_array, var_1);
return 0;
}
void test(void *var_arr, char var_1)
{
int i;
test_struct var_ts;
var_ts.chip = var_1;
var_ts.buffer = var_arr;
for (i=0; i<3; ++i)
printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));
}
Hello, World!
The data values are : 3
The data values are : 7
The data values are : 5
This version below has two warnings but compiles and produces the output expected:
Warning(s):
source_file.c: In function ‘main’:
source_file.c:17:10: warning: passing argument 1 of ‘test’ from incompatible pointer type
test(&test_array, var_1);
^
source_file.c:3:6: note: expected ‘int ’ but argument is of type ‘int ()[3]’
void test(int *var_arr, char var_1);
#include <stdio.h>
void test(int *var_arr, char var_1);
typedef struct {
char chip;
void *buffer;
}test_struct;
int main()
{
int test_array[3] = {3,7,5};
char var_1 = 0x20;
printf("Hello, World!\n");
test(&test_array, var_1);
return 0;
}
void test(int *var_arr, char var_1)
{
int i;
test_struct var_ts;
var_ts.chip = var_1;
var_ts.buffer = (void *)var_arr;
for (i=0; i<3; ++i)
printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));
}
The lower version tells you what the problem was in the first one: passing a pointer to the array instead of a pointer to the first element.
Passing a pointer to the array, which has the type int(*)[3]:
test(&test_array, var_1);
Passing a pointer to the first element, which has the type int*:
test(test_array, var_1);
The code happens to work because the two pointers points to the same address, so the pointer to the array appears to work, but the code is still undefined.
Passing a pointer to the first element is correct, as the array test_array, which has the type int[3] decays to type int* when it is passed to the function.
The warnings are shown because the compiler does static analysis on the code and identified a possible cause of bugs.
When using the void pointer the compiler cannot do this static analysis since it does not know what type is used.
If the datatype is known I would always prefer using this type as pointer instead of the void pointer. I would only use the void pointer when it is acceptable that the pointer can point to anything. In the end this is about personal taste and the code guidelines you follow.
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?