Can a pointer to a string be used in a printf?

84,211

Solution 1

The "%s" format specifier for printf always expects a char* argument.

Given:

char s[] = "hello";
char *p = "world";
printf("%s, %s\n", s, p);

it looks like you're passing an array for the first %s and a pointer for the second, but in fact you're (correctly) passing pointers for both.

In C, any expression of array type is implicitly converted to a pointer to the array's first element unless it's in one of the following three contexts:

  • It's an argument to the unary "&" (address-of) operator
  • It's an argument to the unary "sizeof" operator
  • It's a string literal in an initializer used to initialize an array object.

(I think C++ has one or two other exceptions.)

The implementation of printf() sees the "%s", assumes that the corresponding argument is a pointer to char, and uses that pointer to traverse the string and print it.

Section 6 of the comp.lang.c FAQ has an excellent discussion of this.

Solution 2

printf("%s\n", ptr);

Is this what you want?

By the way, from printf(3), here's the documentation for the s conversion specifier (i.e %s):

If no l modifier is present: The const char * argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating null byte ('\0'); if a precision is specified, no more than the number specified are written. If a precision is given, no null byte need be present; if the precision is not specified, or is greater than the size of the array, the array must contain a terminating null byte.

Solution 3

you should do "printf("S: %s\nPTR: %s\n", s, ptr); " instead of printf("S: %s\nPTR: %s\n", s, *ptr);

difference between ptr and *ptr is: ptr gives you the address in the memory of the variable you are pointing to and *ptr gives rather the value of the pointed variable In this case is *ptr = ptr[0]

this code will show what i mean:

printf("\tS: %s\n\tPTR: %s\n\tAddress of the pointed Value: %x\n\tValue of the whole String: %s\n\tValue of the first character of the String: %c\n", s, ptr,ptr,ptr,*ptr);
Share:
84,211

Related videos on Youtube

andreihondrari
Author by

andreihondrari

I'm a freelance full-stack software engineer. I've been coding for quite a while and I enjoy helping others out! Feel free to email me for anything at: [email protected].

Updated on March 09, 2020

Comments

  • andreihondrari
    andreihondrari about 4 years

    I am thinking of something like:

    #include <stdio.h>
    #include <conio.h>
    #include <stdlib.h>
    
    int main(void) {
        //test pointer to string
        char s[50];
        char *ptr=s;
        printf("\nEnter string (s): ");
        fgets(s, 50, stdin);
        printf("S: %s\nPTR: %s\n", s, *ptr);
    
        system("PAUSE");
        return 0;
    }
    

    Or should I use a for loop with *(s+i) and the format specifier %c? Is that the only possible way to print a string through a pointer and a simple printf?

    Update: The printf operates with the adress of the first element of the array so when I use *ptr I actually operate with the first element and not it's adress. Thanks.

    • Bertrand Marron
      Bertrand Marron almost 13 years
      Please don't use gets. "Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead." (fgets(3)).
    • Jeff Mercado
      Jeff Mercado almost 13 years
      If you don't mind, I tweaked the code to minimize the chance of comments about what you wrote that are not important to the question. Namely using gets() and the return type of main(). You should avoid using gets() at all costs and use other methods such as fgets() (as @Bertrand explains). Also main() should always return int.
  • andreihondrari
    andreihondrari almost 13 years
    well actually printf("%s\n", *ptr);
  • CB Bailey
    CB Bailey almost 13 years
    @AndrewGH: Betrand Marron is correct. *ptr has type char, but %s requires type char* so printf("%s\n", ptr); is correct.
  • Bertrand Marron
    Bertrand Marron almost 13 years
    @Andrew G.H., No. ptr is a pointer to char. *ptr is a char.
  • andreihondrari
    andreihondrari almost 13 years
    I was wondering if I could print that string through a pointer using the %s without any other fuzzle.
  • Bertrand Marron
    Bertrand Marron almost 13 years
    @Andrew G.H., Yes printf("%s\n", ptr). If you don't understand, I strongly recommend you to read a book about pointers and learn to use them.
  • andreihondrari
    andreihondrari almost 13 years
    What I've read is that the folowing identities are true: array equals &array[0] and *array equals array[0] so basically what i understant that I can assign to a pointer the adress of the first element ptr=array_name that basically means that the pointer stores the adress of array_name[0], that is &array_name.
  • andreihondrari
    andreihondrari almost 13 years
    So knowing that, why can't I access the string by *ptr? because *ptr is equivalent to the array[0] ...so I don't understant why use simply ptr?
  • andreihondrari
    andreihondrari almost 13 years
    Yes, of course but, when using printf("%s", array_name) you basically access &array_name[0], isn't it so?... oh nevermind I got it. the printf operates with the adress of the first element of the array so when I use *ptr I actually operate with the first element and not it's adress. Thanks.
  • arthur
    arthur almost 13 years
    @Andrew G.H: printf("%s", array_name) doesn't let you access the &array_name[0] but rather &array_name. The &array_name is the address of the variable of the certain type. The way to process each variable differs according to the type. for Strings (char*) the %array_name but to the first characters like you said, but because of the "%s" , printf has to read array_name til '\0' is found
  • andreihondrari
    andreihondrari almost 13 years
    the identifier of an array is equal to the adress of the array's first element: array_identifier == &array_identifier[0] cplusplus.com/doc/tutorial/pointers
  • arthur
    arthur almost 13 years
    yes of course but it' seems you thought printf("%s", array_name) will access the the first element ... i just try to tell you, that because of "%s" the printf will print all the content of the pointer's variable till it finds the '\0' in this pointer's variable....
  • andreihondrari
    andreihondrari almost 13 years
    doesen't it uses the adress of the first element to do that? I mean every function that I've heard about uses this first adress to determine the rest, because the next elements are consecutively from this point. Any function that uses this system are susceptible to continue counting the elements if no nul byte is found, and that is how buffer overflow occurs. That is why gets is dangerous and can create a B.O.
  • andreihondrari
    andreihondrari almost 13 years
    In the pointers and arrays section, in the link I posted before there is a statement: "In fact, the identifier of an array is equivalent to the address of its first element...".
  • arthur
    arthur almost 13 years
    of course it does that, it uses the adress of the first element to do that.... but i was taking about printf with the "%s" format, which reads the pointer to the end of the last char ...
  • Keith Thompson
    Keith Thompson almost 13 years
    @Andrew: *ptr is only the first character of the string, not the entire string. Most operations that act on strings do so indirectly, via a pointer to the string's first character. If you pass *ptr to a function, the only information that function receives is the value of that first character; it gives the function no way to access the rest of the string. Passing *ptr lets the function access the first character by dereferencing the pointer, the second character by incrementing the pointer and then dereferencing it, and so on.
  • RBT
    RBT over 7 years
    regarding any expression of array type is implicitly converted to a pointer to the array's first element - Although that is true but memory wise program will allocate 4 or 8 bytes (platform dependent) for p variable to store address of w character but that's not the case with s variable. s is able to behave as pointer just because of the compiler trick as compiler knows that an array is always present in contiguous memory blocks. No separate memory allocation happens for s variable which stores the address of h character. Kindly correct me if I've got any of the bits wrong.
  • Keith Thompson
    Keith Thompson over 7 years
    I wouldn't say that s "is able to behave as [a] pointer". s is an array object. The expression s is, in most contexts a pointer expression. For char *p = "world";, sizeof (char*) bytes are allocated for p, and 6 bytes are allocated for array object corresponding to the string literal. You're right that no separate memory allocation is done for s; the declaration char s[] = "hello"; does not create a pointer object.
  • RBT
    RBT over 7 years
    why I said that "s is able to behave as [a] pointer" is because The "%s" format specifier for printf always expects a char* argument and s being an array object still suffices expectations of the argument :). But I got your point. We shouldn't call s a pointer when it is actually an array object.
  • Keith Thompson
    Keith Thompson over 7 years
    @RBT: Think of "array" and "pointer" as adjectives, not as nouns. An array expression can become a pointer expression (the "conversion", which should probably be called an "adjustment", happens at compile time). An array object never becomes a pointer object.