C Array to Pointers - c

Please explain why the below code fails at line 10.
How can I print values of p, i.e. Hello World.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char **p = &ar;
printf("%s\n", *p[0]);
return 0;
}
EDIT:
Just to clarify more on what I want to achieve. I have a function that accepts char** as argument, hence why I want to convert char ar[200] into char**, but the application freezes.

You have declared a character array and assigned value to it. If you just mention the name of the array, you are actually mentioning the base address of this array. Pointers can store address, you can define a char pointer and assign the base address of your character array to it.
for example
char ar[200]="Hello World";
char *p=a; //assign the base address of a to p;
You can then print the string using the %s format specifier with the base address of your character array(string).
printf("%s",a);// print the string "Hello World". here a is the base address
printf("%s",p);//print the string "Hello World". here p is the base address
This will work
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char *p = ar;
printf("%s\n", p);
return 0;
}
Edited for your convenience
char *q=a;
char **P=&q;
printf("%s",*p);
if this is what you want

Arrays already "decay" to the address of their first element in most contexts. This behavior differs from other variables, even from the other aggregates, structs. The reasons are rooted deep in the history of C (namely, no joke, in B1).
One of the contexts though where an array does not decay is when its address is taken: the address operator yields a pointer to array, not a pointer to pointer to char:
char arr[6] = "abcde"; // 5 letters plus '\0'
char (*parr)[6] = &arr; // pointer to array of 6 elements
Curiously enough, dereferencing this pointer twice yields the first char in the array, as if parr were a pointer to pointer to char. The reason is that *parr simply is the original array, and dereferencing that is quite normally its first element. This is likely the source of much confusion:
printf("%c", **parr);
Traditionally (i.e. in the 1970s) pointer was pointer, and their types didn't matter much. (There is a big difference though: What value does parr+1 have?) But it's nice to compile without warnings and to understand what one is doing. So how do we get your requirement, a pointer to a pointer to a char, for printing arr? The answer is, just use a pointer to a pointer!
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char *p = ar; // pointer to char:
// array "decays" to address of first char
char **pp = &p; // pp is a pointer to a pointer to char.
// The point is, it points to the "pointer to char" p.
printf("%s\n", *pp); // *pp is what pp points to:
// p, a simple pointer to char. That's what "%s"
// expects. p is initialized and points to
// the first char in ar.
return 0;
}
1Cf. the interesting paper by Dennis Ritchie, "The Development of the C Language", p.7

gcc main.c -o main
main.c: In function ‘main’:
main.c:9:16: warning: initialization from incompatible pointer type [enabled by default]
char **p = &ar;
^
main.c:10:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s\n", *p[0]);
^
expects argument of type ‘char *’, but argument 2 has type ‘int’ seems very clear :P
You can print your string by changing you program by
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
char *p = ar;
printf("%s\n", p);
return 0;
}

In c ar is equal to &ar, because arrays are basically memory addresses to their first elements.
So you only need a pointer to a char not a pointer to a pointer to a char.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char *p = &ar;
printf("%s\n", p);
return 0;
}

This question is an interesting example of the difference between arrays and pointers. It is common to think of arrays as pointers, but that isn't quite true. The fact that char ar[200] doesn't make ar into a char pointer is why you can't use a char** to point to ar. On the other hand, arrays decay to pointers in function calls, so the following code does work (though it is terribly unmotivated):
#include <stdio.h>
#include <string.h>
void printString(char ar[]){
char **p = &ar; // as in original code
printf("%s\n",*p);
}
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
printString(ar);
return 0;
}

How can I print values of p, i.e. Hello World.
You do not need a pointer to pointer for this purpose. A simple pointer will do.
char *p;
p = ar;
printf ("%s\n",p);

Example of when to use **pointers
#include <stdio.h>
void foo(char **bar)
{
*bar = "some text";
}
int main(int argc, char *argv[])
{
char *temp;
foo (&temp);
printf ("temp=%s\n", temp);
return 0;
}

I explain in the comments of your code.
EDIT: Do not copy following code
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";// technically an array is a pointer, so char *ar and char[] are the same
strcat(ar, " !");// pass the pointer to treat strings
printf("%s\n", ar);// pass the pointer to treat strings
char **p;// here is the problem you were giving the address of your pointer to a pointer of pointer in inline wich makes more confusing
(*p) = &ar; // here is the correct assingment
printf("%s\n", *p);// so here you should pass *p
return 0;
}
EDIT: This solution is far safer in real life situations
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";// technically an array is a pointer, so char *ar and char[] are the same
strcat(ar, " !");// pass the pointer to treat strings
printf("%s\n", ar);// pass the pointer to treat strings
// This solution initializing is better because it avoids editing other variables
char *p = ar;
char **pp = &p;
printf("%s\n", *pp);// so here you should pass *pp
return 0;
}

Related

Difference of char **a and char *a[]

I am new to programming and C in general and the last few weeks I try to get the concept of pointers, arrays and how they are connected.
At the moment I experiment with command line arguments in C and I read here on this platform that argv can be syntactically defined differently, however the semantic stays the same.
int main(int argc, char *argv[])
is equal to
int main(int argc, char **argv)
Okay, but why is my code behaving differently when I try to initialize an array in these ways:
char *s[] = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get as output as expected: o and 3.
But when I initialize the array like
char **s = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get a segmentation fault or other errors which I cannot understand like (near initialization for ‘s’)
I guess you cannot initialize an pointer to a pointer array with 2 asterisks.
Maybe someone can provide me with more information about these relation and how these 2 definitions differ from each other.
They are completely different:
char *s[]
is an array of pointers. Arrays cannot be assigned or used as values
This code will not compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
a++;
}
void bar(void)
{
a1 = a;
}
char **s
is a pointer to a pointer and can be assigned or used as an lvalue.
This code will compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
s++;
}
void bar(void)
{
s1 = s;
}
https://godbolt.org/z/vqxv913WY

Change pointer of pointer in C

I'm trying to write a void function that gets a pointer to a pointer of a string (char**) as a parameter, and changes the original char* so it pointed to another string, lets say "hello".
Below is the code I've written:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_ptr(char **str_ptr)
{
char hello[] = "hello";
char *hello_ptr = hello;
*str_ptr = hello_ptr;
}
int main()
{
char str[] = "yay";
char *str_ptr = str;
char **ptr_to_str_ptr = &str_ptr;
change_ptr(ptr_to_str_ptr);
printf("%s\n", str);
return 0;
}
As you can see, Im getting the pointer to the pointer of the char* "yay", delivering it to the function, and in the function I'm getting the pointer to "hello", and changes *str_ptr (which is the pointer to the original string) to the pointer to hello. But when I print str at the end, it prints "yay".
What am I doing wrong?
(when I debug with printing the addresses, everything seems fine.)
This works:
#include <stdio.h>
void change_ptr(const char ** str_ptr)
{
*str_ptr = "hello";
}
int main()
{
char str[] = "yay";
const char * str_ptr = str;
const char ** ptr_to_str_ptr = &str_ptr;
change_ptr(ptr_to_str_ptr);
printf("%s\n", str_ptr);
}
Note that the string "hello" in this example is read-only because it is a string literal. I added const in a few places so you are reminded of this and the compiler will warn you if you try to write to the string. The pointer str_ptr can be modified, but not the string itself.

What is the meaning of changing char pointer to int pointer

I have the following code from previous exam in c:
int main(int argc, char **argv) {
char s[] = "123";
int* a = (int*) s;
printf(("%x"),*a);
return 0;
}
The output is: 333231
My question is why? how does changing the pointer effect it?
You don't have to declare a separate variable. This would do:
printf(("%x"),(int*)s);
The pointer type dictates how the pointee is interpreted when the pointer is dereferenced.

Make a function that reads (string) input

I'm new to programming and I have an assignment to make a function that reads a name. For some reason the following 'solution' does not work and the output is always something with weird chinese? characters. What went wrong?
#include <stdio.h>
#include <stdlib.h>
void input(char* a);
int main()
{
char name[8];
input(&name);
printf("%s", name);
return 0;
}
void input(char* a)
{
char buff[8];
scanf("%s", buff);
*a = buff;
}
I think the problem is in your
*a = buff;
statement because buff does not have a life outside of your function. so its memory will be lost.. so it is not safe to try and use buff in this way...
[ But as pointed out by #pablo what *a = buff; will do is copy the address of buff and put it into the memory allocated to a, which is really not what you want to do. ]
below should work and do include return from your function
#include <stdio.h>
#include <stdlib.h>
void input(char* a);
int main()
{
char name[8];
input(&name);
printf("%s", name);
return 0;
}
void input(char* a)
{
// char buff[8];
scanf("%s", a);
// *a = buff;
return;
}
one other point is to check if you are sure the name will only be 8 characters long... why not have it as 50 characters?
First off, you should pass the array to the function input() not its address. Secondly, replace scanf("%s", buff) with scanf("%s", a). This will store the string directly in the array you pass to the function.
So, the fixed code should look like:
#include <stdio.h>
#include <stdlib.h>
void input(char* a);
int main(void)
{
char name[8];
input(name);
printf("%s\n", name);
return 0;
}
void input(char* a)
{
scanf("%s", a);
}
The reason why your code doesn't work is that, you try to assign address of the local array buff to the first element of the array that you pass to the function. This shouldn't even compile or the compiler must issue a warning! If your compiler allows it to pass without any of these, that's a disaster.
Finally, the main function should be declared as int main(void) or int main(int argc, char **argv).
*a = buff; doesn't copy buff to a. Use strcpy() as
strcpy(a,buff);
complete code :
void input(char* a);
int main()
{
char name[8];
//input(&name);/** no need to pass & bcz name itself represents address */
input(name);
printf("[%s]", name);
return 0;
}
void input(char* a) {
char buff[8];
scanf("%s", buff);
//*a = buff; /* not valid **/
strcpy(a,buff);
}
This function is a problem:
void input(char* a)
{
char buff[8];
scanf("%s", buff);
*a = buff;
}
buff is local variable that is only valid while input() is running, so
returning this variable is wrong.
*a = buff; is also wrong. *a is the same as a[0], that means it is a
char. buff is an array of char, so you are assigning a pointer to an array
of char to a char variable. That doesn't sound right, it's putting apples in
the oranges box. In fact what is happening is that you are assigning the address
pointed to by buff in the memory pointed to by a.
Your compiler should have warned you about that, don't ignore the
compiler warnings, they are there to help you, not annoy you,
void input(char *a)
{
scanf("%s", a);
}
would be the correct function.
Doing
char name[8];
input(&name);
is wrong, even though the address of name and &name will be the same, but
they will have different types. name decays into a pointer, so it is a
char*. However &name is a pointer to an array of char, a different type.
The compiler should give you a warning like this:
warning: passing argument 1 of bar from incompatible pointer type
note: expected char * but argument is of type char (*)[8]
The correct call is:
input(name);
In general there is one big problem, though: You only declare 8 spaces for the
buffer. If the name is longer than 7 characters, you will have a buffer
overflow. Instead of using scanf I recommend using fgets instead, because
here you have much more control of the input and the memory boundaries.
char name[30];
fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = 0; // removing possible newline
scanf is not always easy to use. A name can be long and have spaces in it.
Specially for a beginner, this can be tricky. fgets is easier to use.
You don't need to pass the address of name since it's a char array. And when you do the copy in input(), you should use strcpy. The following code works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void input(char* a);
int main()
{
char name[8];
input(name);
printf("%s", name);
return 0;
}
void input(char* a)
{
char buff[8];
scanf("%s", buff);
strcpy(a, buff);
}

What is the difference between char **ptr and char *ptr[] in C?

#include<stdio.h>
void display(int n, char *str[])
{
int i=0;
while(i<n) printf("%s ",str[i++]);
}
int main()
{
display(1,"Hello");return 0;
}
when I run this above code I get warnings as
arr.c: In function 'main':
arr.c:11:12: warning: passing argument 2 of 'display' from incompatible pointer
type
display(1,"hello");
^
arr.c:3:6: note: expected 'char **' but argument is of type 'char *'
void display(int n,char *str[])
But then how is it different from
int main(int argc, char * argv[])
And what is the difference between
char **argv and char *argv[]
I am strictly not asking about something like char *argv[100]
As a parameter of a function both char **ptr and char *ptr[] are equivalent, otherwise they are different. Former is a pointer to pointer to a char while latter is an array of pointers to char.
When a string literal is passed to a function, then pointer to its first character (char * type) is passed. You need to change the function's second parameter to char *str.
void display(int n, char *str)
{
// Function body
}
Well, char **ptr is a double pointer (pointer to a pointer) of char while char *ptr[] is an open array of pointer to char.
According to cdel, char **p; gives the result of "declare p as pointer to pointer to char" while char *p[]; gives "declare p as array of pointer to char."
Character strings are always arrays, and arrays are generally always pointers, so the two are generally equivalent which means that **ptr = *ptr[]. What you end up with is an array of an array of chars, or an array of strings. Take main() for instance:
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "some string") == 0) do something;
}
Do some stuff;
return(0);
}
Another way to declare it is
int main(int argc, char *argv[])
Programmatically, it's easier to understand *ptr[] than **ptr.

Resources