In the below code, we get a pointer from strdup(source) and we store it in a pointer named target.
Now, when we print the string using pointer, we don't add * at the beginning of the pointer: why is it so? As I studied whenever we want to dereference any pointer we use *pointer_name. If we add * in the below code, we get an error.
I am very beginner, so pls ans in easy words.
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "Programming";
char* target = strdup(source);
printf("%s\n",target);
return 0;
}
printf expects a char pointer in the place of the %s specifier.
https://en.cppreference.com/w/c/io/fprintf
char* target = strdup(source);
printf("%s\n",target);
Why we don't use *target in the code above?
The explanation is quite simple, as already stated in previous answers: target has type char pointer, which is exactly what printf() wants in the above call.
Now, printf() is a little complicated because its semantic is not simple - basically it accepts zero or more arguments after the first, of any type (possibly applying promotion). But if we use strdup() again, maybe it is simpler:
char* target2 = strdup(target);
Here, if you wrote strdup(*target), the compiler might warn that you are passing a char instead of a pointer to char.
strdup() returns a char*, hence the char* type of target. target holds a pointer to the first character in an array of chars. printf("%s", string) expects string to be a char*, so there’s no reason to do anything to target; just pass it to printf().
If you dereferenced target, you would get a single char (P in this case). printf() would then complain that you had supplied a character instead of a string (pointer to character). Even worse, the program could compile, and then printf() would try to print the string at address P (0x50), which would result in probably unwanted behaviour.
When working with arrays—a string is a type of array—you rarely want to dereference the array.
Related
I'm confused about the way C handles strings and char * vs char[].
char name[10] = "asd";
printf("%p\n%p", &name, &name[0]); //0x7ffed617acd
//0x7ffed617acd
If this code gives the same addresses for both arguments, does it mean that the C compiler takes char arrays (strings) as a pointer to the first char in the array and moves in the memory till it gets the null terminator? Why wouldn't the same happen if we changed the char name[] to char *name? (I know they differ but what makes C take both in a different way?)
I know that arrays can't be assigned after declaration (unless you used something like strcpy, strcat) which is also confusing. Why wouldn't C take them as any other data type? (Something tells me the compiler has a specific addr for it while you can assign char* to whatever location in the mem since its a pointer).
I know that char * have fixed size unlike char[] which makes char * not usable for first argument of strcat.
in C a "string" is an array of type "char" (terminated with \0).
When you are referring to an array in C, you are using a pointer to the first element. In this case (char *).
According to the ANSI-C standard the name of an array is a pointer to the first element.
Being able to write name instead of &name[0] is syntactical sugar.
In the same way accessing an array element writing name[i] is analogue to writing *(name+i).
does it mean that the c compiler takes char arrays (strings) as a pointer to the first char in the array
An array is not a pointer. But an array will implicitly convert to a pointer to first element. Such conversion is called "decaying".
... and moves in the memory till it gets the null terminator???
You can write such loop if you know the pointer is to an element of null terminated string. If you write that loop, then the compiler will produce a program that does such thing.
Why wouldn't the same happen if we changed the char name[] to char *name?
Your premise is faulty. You can iterate an array directly, as well as using a pointer.
If this code gives the same addresses for both arguments, does it mean
The address of an object is the first byte of the object. What this "same address" means is that the first byte of the first element of the array is in the same address as the first byte of the array as a whole.
I know that arrays can't be assigned after declaration (unless you used something like strcpy, strcat) which is also confusing.
Neither strcpy nor strcat assign an array. They assign elements of the array which you can also do without calling those functions.
Why wouldn't C take them as any other data type?
This question is unclear. What do you mean by "C taking them"? Why do you think C should take another data type? Which data type do you think it should take?
char name[10] = "asd";
printf("%p\n%p", &name, &name[0]);
The arguments are of type char(*)[10] and char* respectively. The %p format specifier requires that the argument is of type similar to void* which isn't similar to those arguments. Passing an argument of a type other than required by the format specifier results in undefined behaviour. You should cast other pointer types to void* when using %p.
This question already has answers here:
Char pointers and the printf function
(6 answers)
Closed 1 year ago.
For example, the following code returns an error and a warning when compiled and an int when changed to %d
Warning:
format %s expects argument of type char *, but argument 2 has type int
void stringd() {
char *s = "Hello";
printf("derefernced s is %s", *s);
}
*s is an expression of type char since it's the dereference operator applied to a pointer-to-char1. As a result, it gets promoted to an int when passed to printf; in order to print a null-terminated string, you need to pass the pointer to the first character (i.e. just s).
1 even though s is not a const pointer, you should not try to modify the characters it points to as they may be placed in read-only memory where string literals are stored on some architectures/environments; see this discussion for more details.
The variable s is a pointer to the first out of a series of characters which are consecutive in memory (colloquially referred to as a "string", though it's not quite the same). It's a pointer to a character, thus char *.
Dereferencing s (by doing *s) gives you the first of those characters, h, whose type is now just char. One layer of indirection was stripped away.
Thus, the issue is that you're trying to pass a character (char), where a string (char *) was expected. char * was expected because you used the %s type character in your format string to printf. Instead, you should use %c, which expects single, simple char.
The mistake here is actually quite grave. If you were allowed to pass this 'h' where a char * was expected, you would end up with the ASCII code of 'h' (0x68) being passed where a pointer was expected. printf would be none-the-wiser, and would try to dereference that value, treating 0x68 like a pointer to the beginning of a string. Of course, that's probably not a valid memory location in your program, so that should seg-fault pretty reliability, if it were allowed to happen.
In the book Learn C The Hard Way at excercise 15 there is suggestion to break program by pointing integer pointer at array of strings and using C cast to force it. How can I do it?
Here is a small example. the result depends on the endianness of your system and the size of int. I would expect the first or fourth character to change to the next character in the alphabet.
#include<stdio.h>
int main(void) {
char string[100] = "Somestring";
int *p;
/* Let p point to the string */
p = (int*)string;
/* modify a value */
(*p)++;
/* Let's see if any character got changed */
printf("%s", string);
return 0;
}
It should be pointed out that not all casts are safe and that the result could be implementation defined or undefined. This example is actually undefined, since int could have stricter alignment constraints than char.
When writing portable code you need to take great care when using casts.
The code above could break on any system where sizeof(int) is greater than the string length regardless of alignment issues. In this case, where the string has size 100, we wouldn't expect that to happen in a long while. Had the string been 4-7 bytes it could happen sooner. The jump from 32- to 64-bit pointers broke a lot of old code that assumed that pointers and int were the same size.
Edit:
Is there an easy fix to the alignment problem? What if we could somehow make sure that the string starts in an address that is also suitable for an int. Fortunately, that is easy. The memory allocation function malloc is guaranteed to return memory aligned at an address that is suitable for any type.
So, instead of
char string[100] = "Somestring";
we can use
char *string = malloc(100);
strcpy(string, "Somestring");
The subsequent cast is now safe alignment-wise and is portable to systems where int is smaller than 100.
Note that malloc is declared in stdlib.h, so we should add the following at the top of our code file:
#include<stdlib.h>
That's simply an abusive way of casting.
// setup the pointers to the start of the arrays
int *cur_age = ages;
char **cur_name = names;
What the author of that link meant by "to break program by pointing integer pointer at array of strings and using C cast to force it." He meant that you can write something like this int *cur_age = (int *)names; That is to cast a pointer to pointer to char to a pointer to int. You can do that in C, which allows you to cast from one type of pointer to another type of pointer; but be warned you need to know what you are doing.
Here the author wanted to show how to break a program by pointing a pointer to a wrong type. His example, however, is probably making you more confused rather than helping you to understand pointers.
To cast, use the cast operator: (type)expression. For example, to cast an expression of type double to int:
(int)sqrt(2);
In your specific case, cast names to int* (the type of cur_age) to break the program:
cur_age = (int*)names;
To point incompatible pointer in c you only need to cast it to void.
//array of string declaration
char aStr[50][50];
Int *pint;
//do whatever you need with string array
pint = (*int)(*void)aStr;
I'm writing this from my cell phone.
if you increment your pointer past the allocated memory, you might end up in your program stack and change value to it.
So I need to have a pointer to a value in a const char array. But I can't quite get it to work without errors. Here's the code.
int main (void)
{
const char *alp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *ptr = &alp[3];
printf("%s\n", ptr);
return 0;
}
Edit- Sorry for not mentioning the errors. The thing is I get tons of different errors depending on where I put different asterisks and ampersands. There is no one particular error. One of the more frequent ones I get says
"incompatible integer to pointer conversion assigning to 'char *'
from 'const char';"
In the end I just want "ptr" to be equal to a pointer pointing to "D" in the array "alp".
If you only want one character to print, change the %s to %c and dereference the pointer
printf("%c\n", *ptr);
It's true that you had a character pointer but %s tells printf to print from that pointer until it reads a null character. So we switch to %c which will print one character but it expects a value rather than a pointer to a value.
alp is a pointer to constant char.
ptr is a pointer to a non-const char.
If you want that to work out you would need to change ptr to be defined as:
char const * ptr = &alp[3];
The const is saying that you're not going to change it, but then you're trying to copy the reference to a variable without that limitation. Instead, try:
const char *ptr = &alp[3];
But note that as other posters have already suggested, this code will give you a pointer to a string beginning with the D (e.g. DEFGHI...), not just the character D.
What does (char* )str do in the below code?
/**
* Main file
*/
#include <assert.h>
#include <mylib.h>
int main()
{
const char str[] = "this is my first lab\n";
int ret=1;
ret = my_print((char *)str, sizeof(str));
assert(!ret);
return 0;
}
This code is written by my instructor.
my_print is a function which receives a pointer to a string and the size of that string. I am confused on why do we have to use (char *)str to pass the string to the my_print function. What does it actually do?
It casts away the const.
This means it makes your program likely to crash in case my_print modifies that string since its memory may be marked as read-only. So it's generally a bad idea to remove the const modifier through a cast.
In your case it looks a bit like whoever implemented my_print didn't think that string to be printed would never have to be modified and thus didn't make it accept a const char * argument.
So what you should do instead of the cast is changing the definition of my_print to accept a const char * instead of a char * as its first parameter.
That is "type casting" (or "type conversion"). In other words, it tells the compiler to treat one type as another type.
What this specific conversion does is tell the compiler to treat the constant string as not constant. If the called function tries to modify the string, it may not work, or may even crash the program, as modifying constant data is undefined behavior.
It is a typecast, i.e. it changes the datatype. (char*) means type cast to type "pointer to char"