This question already has answers here:
How to fix error Format specifies type 'char *' but the argument has type 'char'
(2 answers)
Closed 2 years ago.
Trying to understand pointer.
Below, I just want to prove to myself the below
address of str ( &str) = address of where str2 is pointed to(str2)
actual memory of address for str2 is something different(&str2)
However, when I compile below I get seg fault saying "morePointers.c:6:56: warning: format specifies type 'int' but the argument has type 'char *' [-Wformat]"
How can I correct this while proving this in the code?
int main(int argc, char** argv) {
char str = "goodbye";
char *str2 = str;
printf("%d %d %s %d %d\n", &str2, str2, str2, str, &str);
}
In this declaration
char str = "goodbye";
you are trying to initialize an object of the type char with a string literal that in the initialization expression has the type char *.
You have to write
char *str = "goodbye";
Instead of this declaration
char *str2 = str;
it seems you mean
char **str2 = &str;
that is you are creating a pointer that points to the pointer str.
Thus dereferencing the pointer str2 you will get the value stored in the pointer str that is the address of the first character of the string literal "goodbye".
Here is a demonstrative program
#include <stdio.h>
int main(void)
{
char *str = "goodbye";
char **str2 = &str;
printf( "str = %p is the same as *str2 = %p\n", ( void * )str, ( void * )*str2 );
printf( "str2 = %p contains the address of str (&str) = %p\n", ( void *)str2, ( void *)&str );
printf( "The string literal pointed to by str = %s\n"
"is the same as pointed to by *str2 = %s\n",
str, *str2 );
return 0;
}
The program output might look like
str = 0x561655562008 is the same as *str2 = 0x561655562008
str2 = 0x7ffdb7fc57a8 contains the address of str (&str) = 0x7ffdb7fc57a8
The string literal pointed to by str = goodbye
is the same as pointed to by *str2 = goodbye
Pay attention to that using the conversion specifier %d with pointers results in undefined behavior.
This would be the correct code:
#include <stdio.h>
int main(int argc, char** argv) {
char *str = "goodbye"; // a '*' was missing in your code
char* str2 = str;
// you need to use %p for pointer values
// and for each argument for a %p you need to cast to (void*)
printf("%p %p %s %p %p\n", (void*)&str2, (void*)str2, str2, (void*)str, (void*)&str);
}
Typical possible output for this code on a 32 bit system
00FFF710 00996B30 goodbye 00996B30 00FFF71C
Typical possible output for this code on a 64 bit system
0x7ffc8f58ada0 0x555ba93f6004 goodbye 0x555ba93f6004 0x7ffc8f58ad98
Related
this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.
I would like to reverse a String with an pointer to a function, which executes the String reverse.
I have the feeling that I did not grasp the concept of using pointer to variables or functions correctly, so I would be very thankful if someone could expain me, where I am thinking wrong here:
1) Define a pointer to a function:
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
2) Now in my main I define a pointer, which matches the function I defined above:
int main(void) {
char (*functPtr)(char);
functPtr = &strrev;
3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}
Unfortunaly I get all kinds of error message such as:
Ü1.c:29:10: error: array initializer must be an initializer list or string literal
char t[50] = (*functPtr)(pointer[50]);
^
Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
pointer[50] = &str[50];
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
char t[50] = (*functPtr)(pointer[50]);
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
2 warnings and 1 error generated.
1) Define a pointer to a function:
No, you did not define a pointer to function. You defined a function with the name strrev.
2) Now in my main I define a pointer, which matches the function I
defined above:
int main(void) {
char *(*functPtr)(char *);
functPtr = &strrev;
Yes, you defined a pointer to function and initialized it with the address of the function strrev. As function designators used in expressions are implicitly converted to pointers to function then you could write
int main(void) {
char *(*functPtr)(char *);
functPtr = strrev;
3) Now I define the String, which I want to reverse, define a new
pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
Except the definition of the character array that contains a string all other records do not make any sense. For starters the function strrev reverses a string in place. It does not create a reversed copy of the passed to it string.
If you want to declare a pointer that will get the address of the reversed string returned by the function that equal to the address of the original string then you could just write
char *pointer = functPtr( str );
4) Lastly I define a new String and write the result of the function,
which call through the pointer, which points to the pointer to the
function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
You already defined a pointer that will get the value returned from the function. So there is no sense to declare one more array. Moreover arrays do not have the assignment operator. And the function reversed the original string in place. Why are you going to create one more array with the duplicate copy of the original reversed string?! This entirely does not make a sense.
Your program can look the following way
#include <stdio.h>
#include <string.h>
char * strrev( char *s )
{
size_t n = strlen( s );
if ( n )
{
for ( char *first = s, *last = s + n; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char * ( *fp )( char * ) = strrev;
char s[] = "Hello, World";
puts( s );
puts( fp( s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
If you initially wanted that the function would not reverse the original string but make a reversed copy of the original string then in this case indeed there is a sense to define one additional character array that will get the reversed copy of the original string.
In this case the program can look like.
#include <stdio.h>
#include <string.h>
char *reverse_copy( char *s1, const char *s2 )
{
*( s1 += strlen( s2 ) ) = '\0';
while (*s2)
{
*--s1 = *s2++;
}
return s1;
}
int main(void)
{
char * ( *fp )( char *, const char * ) = reverse_copy;
char s[] = "Hello, World";
char t[sizeof( s )];
puts( s );
puts( fp( t, s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
Now the original character array s was not changed while the array t got the reversed copy of the original string stored in the array s.
I summarize my comments in this answer, as it gives more space for details of the comments.
char (*functPtr)(char); should be char *(*functPtr)(char *); as it takes a pointer to a char, not a char. Likewise it returns a pointer.
char *pointer[50]; would be an array of 50 pointers, You want to say "a pointer to an array of 50 chars". In C we don't say that. We just say "a pointer to a char" and don't say how many. So char *pointer; would be enough.
char t[50] = (*functPtr)(pointer[50]); is not correct in C.
You want to assign the result of funcPtr to the array t. But here you mix initialization with assignment.
char t[50]; declares an array of 50 chars. You can initialize it by giving it a value, for example char t[50] = "Hello World"; which will have the compiler copy "Hello World" to the array.
But you try to assign the function pointer to the array. You probably intend to put the result of the function into the array.
Note also that you cannot "assign" an array to another array. You can only copy it.
So the correct code would be:
char *(*functPtr)(char *);
functPtr = &strrev;
char str[50] = "Hello, World";
char t[50];
char *s= funcPtr(str); // call the function and save the returned pointer
strcpy(t, s); // now copy the result to your array.
printf("%s\n", t); // and print it
Note: char str[50] = "Hello, World"; is correct and, just so you'll know, char *str = "Hello, World"; is wrong. Why? Because the second str will point to read-only memory (a "string literal") and any attempt to modify it would abort the program. But here you did it right.
I first copy the second string into the first string. Then I would return string1 pointer from the function. Then I use
%p and (void*)
to print out the starting address of the first string. Is this the right approach?
printf("address: %p \n", (void*)functionstrcpy(stringnumber1,stringnumber 2));
return 0;
}
char *functionstrcpy(char *stringnumber1,char *stringnumber2)
{
//calculation
return stringnumber1;
}
How do I return and print out the .... address of the ... string?
I use "%p" and (void*) to print out the starting address of the first string. Is this the right approach?
Yes. The return is correct and "%p" expects to match a void *. Yet since char * and void * are the same encoding and size, either will work.
printf("address: %p \n", (void*)functionstrcpy(str1,str2));
// or
printf("address: %p \n", functionstrcpy(str1,str2));
Thus the choice is best according to your group's style guide.
The function declaration should look like
char * functionstrcpy( char *str1, const char *str2 );
As you are using already the standard C function strlen then why not to use another string function strcpy? In this case the function can be just a wrapper for the function strcpy without any additional functionality.
char * functionstrcpy( char *str1, const char *str2 )
{
return strcpy( str1, str2 );
}
If you want to write the function yourself without using the standard C function strcpy then its definition can look like
char * functionstrcpy( char *str1, const char *str2 )
{
for ( char *p = str1; ( *p++ = *str2++ ); );
return str1;
}
You may use the returned pointer in the call of printf like
printf("address: %p \n", (void*)functionstrcpy(str1,str2));
because you are just outputting the value of a valid pointer.
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;
}
This is a simple program to copy a string to a new string from a C programming book (Programming in C, S. Kochan). It runs fine, but there is a pointer that I do not see initialized. I'm struggling with pointers here, but I have imbedded in my coding the C golden commandment: "THOU SHALT NOT USE THY POINTERS THAT ARE NOT INITIALIZED". Here is the code:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *to, char *from);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
I was under the impression that all pointers must be initialized in the manner:
*ptr = &variable;
or risk something important in your system being overridden. But I am seeing many programs in my books that are not initializing pointers explicitly, and this makes me very uncomfortable. Please give me some tips about prudent pointer use so I don't destroy my machine, especially anything pertaining to strings. Thanks in advance all!
This confuses you - void copyString (char *to, char *from);. This is just a declaration in main. char *to and char *from in main are not in use so do not worry. The above code is as good as:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *, char *);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
//I do not see where the 'from' pointer is initilized?
When you pass arguments like this copyString(string2, string1); - They will be copied into the args on function call of copyString(char *to, char *from). So in the first call:
copyString(string2, string1); - to = string2, and, from = string1
"A string to be copied."
from--^
And in the second call:
to = string2, and, from = "So is this."
"So is this."
from--^
string2 does not cause any problems (even though it was not initialized) since your overwriting its values (which had garbage values before).
to and from are function parameters, when the function is called, they are assigned the value of the arguments:
copyString(string2, string1);
to is assigned the value of stirng2 while from is assigned the value of string1. Note that even though string2 and string1 has type of char arrays, but they "decayed" into a pointer to the first element when passed as function arguments.
You are correct - all pointer must be initialized as you said.
When you're declaring the strings, as an array of characters as below:
char string1[] = "A string to be copied.";
char string2[50];
string1 and string2 are pointer to arrays of strings. So, they are already pointers.
When you used them in the copyString function, you are already using pointers, and the assignent is done implicitly. So:
to = string2 = &string2[0];
Here is a commented version of your code - the "from" variable has been renamed to source, and the printf's for the pointer values should illustrate the source. But suffice to say that the arguments to the copyString function are provided by the two calls to the function in your main program. The compiler generates code which takes the arguments you provide in the calls to the function with instructions to save these arguments onto the function call stack frame. Then when the function is called, these values are referenced in the function.
#include <stdio.h>
//the char pointer dest is provided as an argument
//the char pointer source is provided as an argument
char*
copyString(char *dest, char *source)
{
if(!dest) return dest;
if(!source) return dest;
printf("dest %x, source %x\n", dest, source);
//for each character in source, until *source == '\0'
for( ; *source; )
{
//assign the char at *dest into *source
//then post-increment source, dest
*dest++ = *source++;
}
//ensure the dest string is terminated
*dest = '\0';
return dest;
}
int main(void)
{
char* copyString (char *to, char *source);
char string1[] = "A string to be copied.";
char string2[50];
printf("string2 %x, string1 %x\n", string2, string1);
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
When you run the program, you will see the locations of the source and destination pointers provided,
$ ./copystr
string2 bff0dbe7, string1 bff0dc19
dest bff0dbe7, source bff0dc19
A string to be copied.
dest bff0dbe7, source 80485f0
So is this.