zeboidlund
zeboidlund

Reputation: 10137

What makes a char * an array of chars?

Normally, if you do the following:

int * i = &someint;

It's just a pointer to a variable.

But, when you do

char * str = "somestring";

it automatically turns it into an array. Is it the pointer which is doing this, or is it just syntactic sugar for initialization syntax?

Upvotes: 12

Views: 655

Answers (6)

mb14
mb14

Reputation: 22596

As people said str is not an array but only a pointer to a char (The first of "something", so s). However there are 2 syntaxics sugar

1- "something" initialize a block of memory with all the characters, **and add \0 at the end. So

char *str = "something";

is syntaxic sugar for

char *str = {'s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', '\0'};
              ^                                          ^^^^^
              |
              +- str

So technically str, is 10 characters long not 9. (Note that str only point to the

2 -

str[5] 

is syntaxic sugar for

*(str + 5)      

Then, there is a convention that most (not all) C-function dealing with strings, expect the last character to \0 (to know where it ends). Some other (see strncpy, need the length as an extra argument and can add or not '\0'.

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 881223

No, the string literal "somestring" is already a character array, almost certainly created by your compiler.

What that statement is doing is setting str to point to the first character. If you were to look at the underlying assembler code, it would probably look like:

str314159:  db   "somestring", 0  ; all string literals here.
: :         : :
            load r0, str314159    ; get address of string
            stor r0, -24[sp]      ; store it into local var str.

In a large number of cases, an array will decay to a pointer to the first element of that array (with some limited exceptions such as when doing sizeof).


By way of example, the following C code:

#include <stdio.h>

int main (void) {
    char *somestr = "Hello";
    puts (somestr);
    return 0;
}

when compiled with gcc -S to generate x86 assembly, gives us (with irrelevant cruft removed):

.LC0:
    .string    "Hello"
    .text
.globl main
    .type      main, @function
main:
    pushl      %ebp                ; Standard set up of stack frame,
    movl       %esp, %ebp          ;   aligning and making
    andl       $-16, %esp          ;   room for
    subl       $32, %esp           ;   local variables.

    movl       $.LC0, 28(%esp)     ; Load address of string in to somestr.

    movl       28(%esp), %eax      ; Call puts with that variable.
    movl       %eax, (%esp)
    call       puts

    movl       $0, %eax            ; Set return code.

    leave                          ; Tear down stack frame and return.
    ret

You can see that the address of the first character, .LC0, is indeed loaded into the somestr variable. And, while it may not be immediately obvious .string does create an array of characters terminated by the NUL character.

Upvotes: 14

Joe McGrath
Joe McGrath

Reputation: 1501

The word you use "normally" is a big part of issue here.

I think part of what may make this confusing is many functions that that take char * are looking for a c style string (ie null terminated character array). Thats what they want. You could write a function that just looked at the character.

Similarly you could write a function that took a int* and treated it as a null terminated array as well, it is just not common. And for good reason because what if you wanted the value 0? in c style strings (meant for display not binary data) you would never want 0.

#include <iostream>

const int b_in_data[]={50,60,70,80,0};

int Display (const int * a)
{
  while ( *a != 0){
    std::cout << *a; ++a;
  }
}    

int main()
{

 int a[]={20,30,40,0};

 // or more like char* = something because compiler is making string literal for you 
 // probably somewhere in data section and replacing it with its address
 const int *b = b_in_data;

 Display(a);
 Display(b);
 return 0;
}

C style strings just chose to terminate instead of passing size, B style strings passed size instead. arrays of ints are generally not null terminated but could be. Comes down to "normally".

Upvotes: 0

Whoami
Whoami

Reputation: 14408

int * i = &someint;

In addition to others comments, Generally, we can say it is pointer to location of size (int). So, When we access value inside 'i'. ie *i, the sizeof(int) memory location is retrieved. Also, the arithmetic calculation is done in the same way. Ie., incrementing the pointer i+1 , increments + sizeof (int). Hence the size of the retrieved data depends on 'data type' of the variable.

Upvotes: 0

Sanish
Sanish

Reputation: 1719

char * str 

is a pointer to a character. When you assign a string to a character pointer, it is pointing to the first character of the string, not the entire string. If the pointer is incremented you can see that it points to the second character in the string. When you print the character pointer, the cout object prints the character and continues printing character until a null character (\0) is seen.

#include <iostream>
using namespace std;

int main()
{
    char *s = "something";
    cout << "before :" << s << endl;
    s++;
    cout << "after :" << s << endl;
}

This program prints:

~/cpp: ./stringarray
before :something
after :omething

Upvotes: 2

cadrell0
cadrell0

Reputation: 17307

It is not a pointer to a variable. It is a pointer to a place in memory. You are creating a variable and storing it in some memory location, then pointing the pointer at that location. The reason it works for arrays is because the elements of the array are stored back to back in memory. The pointer points at the start of the array.

Upvotes: 3

Related Questions