Serket
Serket

Reputation: 4485

What are the differences between char* and all other types of pointers in C?

I've noticed that there are a couple of differences between the way that char* work in C and the ways that all other pointers work in C. One difference, for example is this: When printing out the char pointer itself, it returns it's value until it is terminated as such: Code:

char* var = "Hello World";
printf("%s", var);

Output:

Hello World

But when doing the same on other pointers, it returns the address of the value stored inside like so: Code:

int var = 5;
int* pVar = &var;
printf("%d", pVar);

Output

//Random memory address

I also noticed that you cannot directly declare pointers that aren't char* like this:

int* var = 5;

Could someone list all the differences between these pointers and why these differences exist? Thanks

Upvotes: 0

Views: 571

Answers (2)

Botahamec
Botahamec

Reputation: 278

Let's go through each of your questions one by one.

Printing

In your first code snippet, you show that printf is capable of printing strings. Of course it printed a string. You gave it a %s which is meant to be a string. But first, what is a string? To explain that, we need to understand arrays and chars.

What's a String?

First, what's a char? A char is a singular character (or an 8-bit number, but for our purposes it's a character). A character can be a letter (a, b, c)m or any other symbol (?, !, ., numbers, there are also some control characters). Typically, if you only needed one character, you'd declare it like this:

char letter_a = 'a';

So what is an array? An array is a group of values all next to each other. Consider the following code:

int int_array[] = int[50];
int_array[0] = 1;
int_array[1] = 2;
...

In this example, what is int_array? The answer seems obvious. It's an array. But there's more to it than thar. What if we do this?

printf("%d\n", *int_array);

It prints out 1. Why? Because int_array is actually just a pointer to the first element of the array.

So why am I talking about arrays? Because a string is just an array of characters. When you run char* string = "Hello!", you just create an array that looks like this: ['H', 'e', 'l', 'l', 'o', '!', '\0']. C knows that the string has ended once it reaches the null symbol ('\0').

In your first snippet, var is a pointer to the letter 'H', and the print statement keeps printing characters until it reaches null.

What about the second snippet?

%d doesn't dereference the variable like %s does. It just prints a number as a signed integer. The integer in this case is the memory address of your integer.

Why cant you assign pointers?

You can. You'll get a warning, and it will probably cause a segmentation fault, but you can try it. I compiled your code example using clang and this is what I got:

test.c:1:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main() {
^
test.c:1:1: note: change return type to 'int'
void main() {
^~~~
int
test.c:2:7: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Wint-conversion]
        int* var = 5;
             ^     ~
2 warnings generated.

I will not dare try to run it though. Basically what you just did is try to access the fifth location in memory, which is most likely some OS stuff. You don't have access to that

Why did it work for the string?

Because it doesn't point to a specific location. It points to the location of the string that C made for you. Your code is roughly equivalent to this:

char h = 'H';
char e = 'e';
...
char* var = &h;

Upvotes: 2

mukunda
mukunda

Reputation: 2995

char* is no different from other pointer types. It just points to a single character. Most string operations in C treat that as it pointing to a sequence of characters, and read it until a null-terminator is found.

A pointer to an int can mean a pointer to one int value OR it can mean the pointer to a start of a sequence of ints, OR it can point to nothing, which is a null pointer. A pointer doesn't hold a length, you need to know how long something is before you read from additional indexes. C strings use the null-terminator to signal the end.

You can't do int *var = 5 because that doesn't make sense (actually, if you cast it like int *var = (int*)5, it might make sense if you want to access some I/O register mapped to that exact address 0x00000005 on an obscure system). A pointer's value holds a memory address. What you can do instead is make an integer value, first, like int myInt = 5; and then int *myPointer = &myInt; You can access the 5 through the indirection operator *.

Pointers have a lot of uses, especially when passing data around to different methods. Say you have a data structure that is 500 bytes. You can either copy all of that data around everywhere, or you can just pass a single pointer value so everything can operate on it in-place. Pointers are also your basic pass-by-reference feature, especially useful when returning multiple values from a function. In C APIs you'll commonly see pointers accepting single ints as function parameters, and those are designated outputs for the function.

The %s format symbol for printf is looking for a pointer to a string, which is normal char* pointer, but it expects it to be more than one character until the null terminator. The %d format symbol is asking for a single int value, so when you pass a pointer into there, it is treating it like an int value – which, mind you, is undefined behavior. %p is meant to read a memory address (pointer), not %d.

The main difference between each pointer type is the size of each memory cell for indexing arithmetic. Indexing a char pointer, e.g. chars[10] will return the 11th char, and on most modern systems char is 1 byte, so it will return the 10th byte. Indexing an int* pointer uses a wider stride, typically 4-bytes per index, so myInts[10] will return the 11th int value over from the pointer address, but each memory step here is 4 bytes. Sometimes people just cast to a byte-sized pointer for the convenience of measuring bytes when indexing an array, and then cast back to the type they want to read.

Upvotes: 1

Related Questions