This should copy a string but prints garbled results. Can anyone help me out?
int main () {
const char *a = "Hello\n";
const char *b = "World\n";
strncpy(&b, &a, strlen(a));
printf("%s %s", a, b);
return 0;
}
I expect "Hello Hello" but the terminal prints:
\
Hello
GCC prints an warning about a and b having incompatible pointer types even though strncpy's signature:
char * strncpy(char *s1, const char *s2, size_t n)
asks for 2 char pointers. Is that because arrays are always char** as mentioned in https://stackoverflow.com/a/20213168 ?
You are passing char ** twice where char* is expected.
&b takes the address of b, with b being a char*, the address of a char. So &b is char **. The same issue appears for a.
Update:
Just saw b isn't an array but a pointer which points to a "string"-literal. The latter are constant, you cannot change them, so copying to a literal's address (what the code actually does not, because of the misplaced &-operator in frot of the b) has to fail.
To get around this define b like this
char b [] = "World\n";
Is that because arrays are always char** [...]
Arrays aren't "always char **".
If an array is passed as argument to a function it decays to a pointer to it's first element. So
char b[] = "test";
would decay to a
char * pb
with pb pointing to the char 't', the first characters of `"test".
Two problems:
You should not copy into a buffer pointed by const char *, as it is a constant buffer.
The arguments for strncpy are char *s, but you passed char **, thus overwriting the pointers themselves, not the content they point to.
Compile your code with -Wall to see warnings that will tell you how to fix this.
Two issues:
1) You should use strncpy(a, b, strlen(a)), if a is a char* and b a const char*. The compiler error you're getting alludes to this.
2) You have undefined behaviour. You've allocated const char* string literals. A compiler may put them in read-only memory. And an attempt to modify either of them is not allowed: even a single element change could cause a program crash.
One remedy would be to use char* b = malloc(/*ToDo - your size here*/);. Remember to free the memory once you're done with it.
Related
I'm having some trouble passing a valid value to the qsort function but can't quite figure out what's going wrong with it. Here is what I have so far:
int main(void)
{
char* strings[4] = {"Onus", "deacon", "Alex", "zebra"};
printf("%zu\n", sizeof(strings));
qsort(strings, 4, 8, scmp);
}
int scmp(const void *p1, const void *p2)
{
printf("%s\n", (char*) p1);
return 0;
// ignore return value -- I'm just looking to print the string.
}
It just seems to print gibberish when I do this. Is this because qsort expects a value a pointer to a value and I'm passing it a pointer to a (char) pointer? What would be the correct way to reference it then?
It seems instead it should be: printf("%s\n", *(char* const*) p1); ? This is from some trial-and-error, though not sure why that works -- i.e., the *(char**).
For example, for passing an int I can do:
const int *v1 = p1;
But then a char* needs to be:
const char *s1 = *(char* const *) p1;
Why not just const char *s1 = (char*) p1; ?
strings is an array of pointers to char. The comparison function for qsort gets passed pointers to the two elements of the array that should be compared. Since the elements of the array are pointers to char, the arguments p1, p2 to scmp are pointers to (const) pointers to char, and should be cast to char ** (or rather char * const *).
What needs to be passed to printf is the pointer to char itself, so you have to dereference the argument to get that pointer. If you wanted to look at the individual characters of the string, you'd have to dereference again. There are two *s in the name of the type, so you have to apply * two times to get back to the underlying primitive type.
printf("The first character of the string is %c\n", **(char * const *)p1);
I was studying "C complete reference" by Herbert Schildt and got stuck on the "const" explanation due by the pointer * he used at the same time with the const explanation.
here is the code he used:
#include <stdio.h>
void dash(const char *str);
int main()
{
dash("this is a test");
return 0;
}
void dash(const char *str)
{
while (*str)
{
if (*str == ' ')
{
printf("%c", '-');
}
else
{
printf("%c", *str);
}
str++;
}
}
I've tried to search about the pointer * and got some answers about adresses but why did he use it in this example? His book didn't explain this and i haven't found other examples with this kinda use of pointer *.
Other question is, why is the loop "while (*str)" correct if it has no condition?
const char *str in a parameter declaration indicates that the function will not try to modify the values that the str pointer points to. This means that you can call the function with a constant string. If you don't have const in the declaration, it means that the function might modify the string, so you can only call it with writable strings.
As an example, a function like strcpy() declares has const on the second parameter (the source string), but not on the first parameter (the destination). It can (and usually does) modify the destination, but not the source.
Many people are confused when start learning C
const char *ptr
It is a pointer which is referencing the const char. The pointer can be modified. But is you try to write to the referenced object the compiler will complain: https://godbolt.org/z/d9znF-
Example:
const char c;
const char *ptr = &c;
*ptr = 'p'; // -- illegal - the compiler will complain
ptr++; // -- legal
to declare the constant pointer to the not constant object:
char * const ptr;
now ptr cannot be changed but the referenced object can: https://godbolt.org/z/h7WWex
char c;
char * const ptr = &c;
*ptr = 'p'; // -- legal
ptr++; // -- illegal - the compiler will complain
to declare const pointer to const object
const char * const ptr;
now the pointer and the referenced object cannot be modified: https://godbolt.org/z/x2xBcZ
const char c;
const char * const ptr = &c;
*ptr = 'p'; // -- illegal - the compiler will complain
ptr++; // -- illegal - the compiler will complain
It's a way of promising that the content the pointer is pointing at will not be altered. It's also a way of suppressing warnings without explicit casts.
Consider this:
void dash(char *str) // Removed const
{
// Code
}
int main() {
const char p[] = "this is a test";
dash(p);
}
Now the compiler will emit this:
k.c: In function ‘main’:
k.c:23:10: warning: passing argument 1 of ‘dash’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
23 | dash(p);
| ^
k.c:4:17: note: expected ‘char *’ but argument is of type ‘const char *’
4 | void dash(char *str)
| ~~~~~~^~~
Since you're not writing to it, this warning is nothing to worry about. But it's good practice to avoid warnings. In this case, we have two alternatives. Either the function may modify the string or it may not. If there's no way it will modify it, then there's no reason to explain to the compiler and the reader that this indeed is the case.
Sidenote. String literals, like "this is a test" has undefined behavior if you modify them, so the program might crash (or not). However, their type is is of type (char*) with no const. The reason is backwards compability. In C++, their type is const char*
Note that the const is a promise by convention, not by the compiler. This code will modify the original string and also compile without warnings:
#include <stdio.h>
void foo(const char *str)
{
// Casting comes with great responsibility
// You're just saying to the compiler
// "Trust me and shut up"
char *ptr = (char*) str;
ptr[2]='A';
ptr[3]='T';
}
int main()
{
const char p[] = "this is a test";
foo(p);
puts(p);
}
output:
$ ./a.out
thAT is a test
As I said, the above will compile without warning. If you remove the cast, you'll get this:
k.c:5:17: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
5 | char *ptr = str;
| ^~~
Do note that since p is declared as const this is undefined behavior. However, you instead write main like this:
int main()
{
char p[] = "this is a test";
foo(p);
puts(p);
}
then, the program is completely valid. And even though you pass a writable string to the function foo, you'd expect it to not change, since foo takes a constant pointer as argument. But as you can see, such things can be bypassed.
Be very careful with void pointers
Note that this is perfectly valid for ANY type T:
T x;
T *p;
p = (void*) &x;
This is because you can safely cast a pointer to void and back. However, this is NOT valid in the general case:
T x;
Q *p;
p = (void*) &x;
However, because of the cast, you will not get a warning. But this code invokes undefined behavior.
Moral lesson
Casting is NOT the goto solution for warnings. Instead, you should REALLY carefully consider if your cast match your intentions. If you're intentions here is to just get rid of the warning, the right solution is to remove the const for the parameter. If you're intentions with adding the cast is "I know that this function promises to not modify the argument, but I have good reasons for both promising that and then instantly break that promise" then a cast is correct.
Real world example
Just to give a real world example of how it can go wrong. I looked in this question where I saw this:
void * func_return();
void (*break_ptr)(void) = (void *)func_return;
I told OP that the cast is wrong. I got the response that without a cast, the compiler complained. Well, it complained because the pointer is WRONG. The function prototype declares a function taking an unspecified number of arguments and returning a void pointer. The function pointer is a pointer to a function taking NO arguments returning nothing. So in this case, the proper pointer declaration and initialization would be this:
void * func_return();
void *(*break_ptr)() = func_return;
But this would probably be better:
void * func_return(void);
void *(*break_ptr)(void) = func_return;
Note that since a pointer of any type can be safely cast to void* and back. But in this case OP was not casting it back, but to another type. If OP had done it correctly, the cast would just be clutter, but in this case it did hide the REAL error.
In c we can manipulate an array like a pointer with the right pointer arithmatic like he used and we can manipulate it like an array!
const char *str
is a pointer to const char OR an array of const char data types!
In a function, all parameters are passed by value (arrays are no exception). When you pass an array in a function it "decays into a pointer". And when you compare an array to something else, again it "decays into a pointer"
so we can write the while loop again in different way:
void dash(const char *str)
{
int i = 0;
while (str[i])
{
if (str[i] == ' ')
{
printf("%c", '-');
}
else
{
printf("%c", str[i]);
}
++i;
}
}
Now, the first syntax (with the pointer deref operator * is more effecient than array syntax).
in general array name or the address of the first array element (of any type), can decays to a pointer of the same data type!
In his implementation, he behaves the str as a const char pointer, in the while loop he is derefrence the pointer (like str[i], with the brackets) and in the last line (str++) he is moving the pointer to points to the next char element (which usualy knwon as pointer arithmetics).
In this case, read the definition from right to left:
const char *str // str is a pointer to a const char
The address of str can change while the char it points to cannot.
To answer you other question, while (*str) will continue to interate until *str == '\0'. '\0' is used to mark the end of a string in C.
What the program does, if you're unsure, is print it, replacing ' ' with '-'. In your example, "this-is-a-test" would be printed. Note: the string "this is a test" is not modified.
The * is related to pointers but it has two uses.
In the declaration, * is used to declare the pointer type, as in:
const char *str;
Where str is a pointer to a const char (or multiple const char stored in sequence, C doesn't care about the difference).
In an expression, * is used to dereference a pointer, get the value it points to. As in:
printf("%c", *str);
Where *str is that const char itself that the pointer str is pointing to.
Related to pointers, there's also & that does the other way around. It gets the pointer of any value you have stored in memory.
The importance of const here is not related to pointers, it's related to the fact you're passing a string literal to dash(). Unlike strings that are stored in the heap or the stack, string literals cannot be modified and should be treated as const for their immutability.
main()
{
const char **a = {"string1","string2"};
printf("%c", *a); /* prints s */
printf("%s", a); /* prints string1 */
printf("%s", a+1);/* prints ng1 */
}
GCC v4.8.3 prints "%s" for the last printf, where as http://codepad.org/ prints "ng1".
I thought that the code will create an array of pointers to two strings and the base address assigned to a, which allows normal pointer arithmetic. but it seems that there is something wrong with the assumption.The first printf suggests that my assumption is wrong. can anyone explain why this behavior is observed? ( note that VS 2012 has thrown an error saying too many initalizers where as GCC has thrown a warning for incompatible pointer assignment). I am aware of the warning due to incompatible pointer assignment.
const char **a is not an array of pointer to two strings. It declares a to be a pointer to pointer to const char.
const char **a = {"string1","string2"}; //No memory is allocated to store string literals
will invoke undefined behavior and you may get either expected or unexpected results.
To declare a as an array of two pointers you need to change the declaration as
const char *a[] = {"string1","string2"};
The memory range in your program's stack looks like this: (notice that it is not allocated before assignment which is wrong)
char** a = {s, t, r, i, n ,g, 1, \0, s, t, r, i, n, g, 2, \0}
Therefore when you print the command:
printf("%c", *a);
You are dereferencing the first character of the string which is 's'.
On the other hand, when you print the command:
printf("%s", a);
you are printing a string that starts at pointer a and finishes at '\0'. That's why you see the output 'string1'.
Lastly, when you type "a+1" you increase the pointer in one step (example here: How to increment a pointer address and pointer's value?). in this case because char** is a pointer, and every pointer is 4 byte, the "+1" jumps 4 chars forward.
Therefore when you print the command:
printf("%s", a+1);
The printf starts at the pointer 'a' + 4 bytes and ends at '\0'. That's why the output is 'ng1'.
Hope it was clear enough.
This is due to the following peculiar initialization performed by GCC.
please see int q = {1,2}; peculiar initialization list. the statement const char **a = {"string1","string2"}; results in a being treated as if const char **a = "string1". this solves the mystery as *a would print 's', a would print string1.
I'm trying to understand the mistake in the following code. The code is supposed to switch between two arrays.
What I saw is that it switches only the first 4 bytes. Is the following correct?
Passing &num1 or num1 is the same (both pass the address of the first element in the array).
The (char**) casting is wrong. That's because when you pass and array you pass the address it's laid in. So you actually pass here a void*.
How can I actually switch between these two arrays only by pointers? Is thatpossible?
I know it is possible if from the beginning I had defined char **num1 and char **num2. But I want it to stay with the array notation!
#include <stdio.h>
void fastSwap (char **i, char **d)
{
char *t = *d;
*d = *i;
*i = t;
}
int main ()
{
char num1[] = "hello";
char num2[] = "class";
fastSwap ((char**)&num1,(char**)&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
return 0;
}
Passing &num1 or num1 is the same (both pass the address of the first element in the array). Am I correct?
No. The first one is a pointer to the array itself (of type char (*)[6]), whereas in the second case, you have a pointer to the first element (of type char *; an array decays into a pointer to its first element when passed to a function).
The (char*) casting is wrong
Indeed, you are casting a char (*)[6] to a char **.
So you actualy pass here a void (Am i correct?).
No. Non sequitur. I don't see how the void type is relevant here. You have pointers, arrays, and eventually pointers to arrays.
Arrays are not pointers. Your code is trying to swap arrays, which does not make sense, since assignment to arrays is not permitted. What you probably want is
I. either get pointers to the first character of each string, and then swap the pointers themselves, like this:
void swap_pointers(const char **a, const char **b)
{
const char *tmp = *b;
*b = *a;
*a = tmp;
}
const char *p1 = "hello";
const char *p2 = "world";
swap_pointers(&p1, &p2);
II. Or use actual arrays, and you swap their contents:
void swap_contents(char *a, char *b, size_t n)
{
for (size_t i = 0; i < n; i++) {
char tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
char a1[] = "hello";
char a2[] = "world";
swap_contents(a1, a2, strlen(a1));
Also, you may want to read this.
1. Passing &num1 or num1 is the same (both pass the address of the first element in the array)
Not true, &num1 gives you a pointer to a pointer that points to the entire character string "hello" (char*[6]) while num1 is just a pointer to the character block "hello" (char[6]).
2. The (char*) casting is wrong. That's because When you pass and array you pass the address it's laid in. So you actualy pass here a void (Am i correct?).
It is still not a void, it's just a pointer to a character pointer. If it were void, then it would be perfectly valid to do something like void** myVoid = &num1. This will cause a syntax error unless you explicitly typecast your char** to a void** before you assign it.
The problem is your explicit type casting &num1 as a char** which is not correct, it is a char*[6]. But of course, you can't declare a variable as a char*[6] so it can't be used in this way. To fix it you need to declare your num1 and num2 as:
char* num1 = "hello";
char* num2 = "class";
instead and keep everything else the same. In fact, with this change there is no need to typecast your &num1 as a char** because it already is that.
Can somebody tell me why this program does not work?
int main()
{
char *num = 'h';
printf("%c", num);
return 0;
}
The error I get is:
1>c:\users\\documents\visual studio 2010\projects\sssdsdsds\sssdsdsds\sssdsdsds.cpp(4): error C2440: 'initializing' : cannot convert from 'char' to 'char *'
But if I write the code like that:
int main()
{
char num = 'h';
printf("%c", num);
return 0;
}
it's working.
char *num = 'h';
Here, the letter 'h' is a char, which you are trying to assign to a char*. The two types are not the same, so you get the problem that you see above.
This would work:
char *num = "h";
The difference is that here you're using double-quotes ("), which creates a char*.
This would also work:
char letter = 'h';
char* ptrToLetter = &letter;
You should read up on pointers in C to understand exactly what these different constructions do.
char * is a pointer to a char, not the same thing than a single char.
If you have char *, then you must initialize it with ", not with '.
And also, for the formatting representation in printf():
the %s is used for char *
the %c is only for char.
In thefirst case you declared num as a pointer to a char. In the second case, you declare it as a char. In each case, you assign a char to the variable. You can't assign a char to a pointer to a char, hence the error.
'h' = Char
"h" = Null terminated String
int main()
{
char *num = "h";
printf("%s", num); // <= here change c to s if you want to print out string
return 0;
}
this will work
As somebody just said, when you write
char *num = 'h'
The compiler gives you an error because you're trying to give to a pointer a value. Pointers, you know, are just variables that store only the memory address of another variable you defined before. However, you can access to a variable's memory address with the operator:
&
And a variable's pointer should be coerent in type with the element pointed.
For example, here is how should you define correctly a ptr:
int value = 5;
//defining a Ptr to value
int *ptr_value = &value;
//by now, ptr_value stores value's address
Anyway, you should study somewhere how this all works and how can ptrs be implemented, if you have other problems try a more specific question :)
When you are using char *h, you are declaring a pointer to a char variable. This pointer keeps the address of the variable it points to.
In simple words, as you simply declare a char variable as char num='h', then the variable num will hold the value h and so if you print it using printf("%c",num), you will get the output as h.
But, if you declare a variable as a pointer, as char *num, then it cannot actually hold any character value. I can hold only the address of some character variable.
For example look at the code below
void main()
{
char a='h';
char *b;
b=&a;
printf("%c",a);
printf("%c",b);
printf("%u",b);
}
here , we have one char variable a and one char pointer b. Now the variable a may be located somewhere in memory that we do not know. a holds the value h and &a means address of a in memory The statement b=&a will assign the memory address of a to b. Since b is declared as a pointer, It can hold the address.
The statenment printf("%c",b) will print out garbage values.
The statement printf("%u",b) will print the address of variable a in memory.
so there's difference between char num and char *num. You must first read about pointers. They are different from normal variables and must be used very carefully.