C pointer manipulation for strings gives unexpected output - c

The following two programs use some basic pointer manipulation. But they perform differently.
#include<stdio.h>
#include<string.h>
int main(void){
int a = 1;
int b = 2;
int *pb, *pc;
pb = &a;
pc = pb;
pb = &b;
printf("%d %d\n", *pb, *pc);
}
This program prints two different numbers(1 and 2) as expected while,
#include<stdio.h>
#include<string.h>
int main(void){
char *ptr, s[10];
ptr = s;
gets(s);
printf("%s %s\n", ptr, s);
}
This program prints the same string two times, whereas it also must have printed different strings.
Why this difference?
How does gets() read a string?

The second example only contains a single string buffer, the array s.
Making ptr point to s doesn't in any way create a second copy of the character data, so when you print both ptr and s, they result in the same string since they evaluate to the exact same address.

After your code runs this:
ptr = s;
ptr points to the beginning of s, so when you invoke printf() you get the same address passed twice there - no wonder the same is being printed twice.

In your second example you have only one array (s) plus a second pointer pointing to the same memory. The two addresses ptr and s are identical and so of course using then in printf() results in the same output. In your first example you have two different integers which can hold different values.

Because those two character pointers are still pointing to the same memory. You are just assigning data to the pointed memory.
But in the case of that integer pointer, you are changed the memory address pointed by the first pointer.
If you did like this:
pb = &a;
pc = pb;
*pb = 7;
It'll print 7 in both case. This is what you did with the character pointer.
Explanation with images:
When you did pb = &a; pb will point to the memory address of a.
When you did pc = pb; pb & pc will point to the memory address of a.
When you did pb = &b; pb will point to the memory address of b. But pc will still point to memory address of a.
Disclaimer: I have attached images with the answer, there is some technical issues in SO. That is why the 3 images are not showing. Check https://meta.stackexchange.com/questions/186466/intermittent-error-with-imgur-when-uploading-images

This program prints the same string two times, whereas it also must have printed different strings.
It mustn't. In your first example, the pointers point to different objects. In the second one, the explicit pointer and the one s decays into point to the same array in memory (obviously...)

Related

C: append char* to char**

I'm really new to C pointers and I'm coming from Java/C++. I am trying to append a char* c to a char** cArray. Here is kind of what I have so far:
char **cArray = "abc";
char *c = "def";
cArray += &c;
printf("%s", cArray)
and output should be: abcdef
My question is, How do I append a char * to a char ** in C?
Thank you for any tips you have!
You seem to have a misunderstanding of what a pointer and an array are. First lets start with an array. An array is a contiguous fixed-size block of memory. That is to say, an array is a constant number of values next to each other.
So, to start with, the idea of "Appending" an array makes sense in the way that you can add an item to the next empty spot in an array. But it would not be right to say the array is growing. An array is not the equivalent of Java's Array List.
Lastly, I will point out static arrays are declared with:
int val[3];
Where 3 can be any other constant value interpreted as a size_t.
Next, lets discuss pointers. Pointers are not arrays, do not confuse the two- although many people find it comforting to think of them as interchangeable (and for the most part you can get away with it!). However, this is one of the cases where they are not. So what are pointers?
Pointers denote the location of a value in memory. So, a pointer could say point to an element in our val array we created above. If we created a pointer to point at each element in our val array and we printed them all to stdout we would see that they are all 4 bytes away from each other. This is because arrays have their values located right next to each other (contiguous in memory) and sizeof(int) would return 4 (on my system).
Your main misunderstanding seems to be that pointers need to point to anything at all. They do not. Just like you can have a value which holds no information (or all of the bits are set to 0), you can surely have a pointer that points no nowhere at all. As a matter of fact that's exactly what you do.
char **cArray = "abc";
char *c = "def";
cArray += &c;
printf("%s", cArray);
Okay, lets take this apart line by line. First you declare a char ** called cArray and initialize it to "abc". Well, your variable cArray is a pointer to a pointer. The value "abc" I believe is a const char*. Therefore, you probably don't want to assign a pointer to a character as a pointer to a pointer. The consequence being, the value "abc\0" will be interpreted as another memory address. This, obviously, will not point to anything useful and accessing this memory would result in a seg fault.
Next, you initialize c to be a cstring containing "def".
Finally, you increment the address pointed to by cArray by whatever address "def" happens to be located at. So now, cArray is no longer even pointing to "abc" at all (nevermind interpreting it incorrectly).
Then we try to print some block of memory pointed to by cArray that is in no way even remotely close to any of the bits our program wants to be touching.
All of this said, say I had two cstrings and I wanted to get a third such that it is the first appended to the second:
char* a = "abc";
char* b = "def";
size_t sizeA = strlen(a);
size_t sizeB = strlen(b);
size_t size = sizeof(char) * (sizeA + sizeB + 1); //Size of our new memory block large enough to contain both a and b.
//Leave additional space for null terminator
char* c = malloc(size); //Actually allocate new memory
memcpy(c, a, sizeA); //Copy a into the first half of c
memcpy(c + sizeA, b, sizeB); //Copy b into the second half
c[sizeA + sizeB] = '\0'; //Assign null terminator to last character
printf("%s", c);
free(c); //Never forget

I need a greater understanding of what a pointer actually points to

What is the actual value of pointer:
char *ptr;
And it's pointing to a memory address, correct?
Not yet; it's uninitialized.
What you're asking is like asking what number int i; refers to.
I will try to explain in a simple way, (sorry if my English is not god enough i am learning)
Let say you have an array of characters:
char a[5];
Then you want to create a pointer to the address of the first element:
char *p = &a[0];
Now since the name of an array is a synonym for the location of the
initial element you can rewrite to the following statement:
char *p = a;
Now here is where magic takes place, as the previous character pointer points to the address of the first element you can do stuffs like the following:
instead of getting the 'i'-th element from a[i], you can move the pointer 'i' places to reference the address of the value contained in the 'i'-th position and then get it's value:
char value = *(a + i);
Font(The C programming language 2nd Edition, Chapter 5)
char *ptr;
It is not pointing any memory address until it is initialized;
But you can use it to point an address.
Suppose,
int i=0;
i has an address in memory. if it become 0xFFFF0 then when you write
ptr=&i;
then your pointer points to address 0xFFFF0 .
now suppose,
int array[5]={0}; is an array.
then if you write-
ptr=array;
then ptr points to the starting address of array because array name is an address.
Yes, it is pointing to the address of the variable.
The variable might be on the stack if the variable is declared inside a function, or at the top of RAM if declared at the top level.
As the other answers point out, you haven't made it point to anything yet, so dereferencing the pointer will likely result in a segmentation fault.
You need to do something like
char ch;
char *ptr = &ch;

The following C program regarding pointers is not working

#include<stdio.h>
int main(void)
{
int *pc;
*pc=100;
printf("\n Address of Pointer : %d",pc);
printf("\n Contents of Pointer : %d",*pc);
}
When I run the code in eclipse, it is saying "Pointers.exe has stopped working". What is the error?
Assigning a value to *pc is particularly dangerous. If pc contains the valid memory address , then the assignment
*pc = 100;
will attempt to modify the data stored at that address.
If the location modified by this assignment belongs to the program, it may behave erratically; if it belongs to operating system, the program will most likely crash.
Your compiler should raise a warning that pc is uninitialized.
Change it to:
int a;
int *pc;
pc = &a;
*pc = 100;
Your pc pointer was not initialized in your program.
Moreover the way your are printing a pointer value is incorrect, use this:
printf("\n Address of Pointer : %p", (void *) pc);
You forgot to point pc to somewhere useful. When you write
int *pc;
The compiler creates a pointer for you. The pointer points somewhere in memory, and you have no way of knowing where. Chances are, it points to a bad place in memory. When you overwrite it with *pc=... you overwrite a place in memory that shouldn't be overwritten.
So you need to have pc point somewhere.
int a, *pc=&a;
will do the trick. Now the compiler prepares an int for you then and you point pc to it. That way, when you write through the pointer, nothing bad will happen - you're writing on an area of memory that you know is safe.
Another way to initialize pc is like so:
int *pc = (int*)malloc(sizeof(int)); // Allocate an integer on the heap
Now *pc=100; will also work. Just don't forget to free(pc) when you're done.
You have:
int *pc;
*pc=100;
When you define the pointer to integer pc above, this pointer is not initialized, so it points to some memory that you have not allocated and you have not the right to access.
So your executable is crashing.
Just use a valid pointer, e.g. you can allocate some heap memory using malloc(sizeof(int)) (and later release it using free()), or just use stack-based memory for local automatic variables, e.g.:
/* An integer stack-allocated variable */
int n = 64;
/* Pointer to that integer */
int * pn = &n;
/* Change its value */
*pn = 100;
Moreover, to print an address, considering using the %p specifier for printf().
e.g.:
#include <stdio.h>
int main(void)
{
int n = 64;
int *pn = &n;
printf("n (before): %d\n", n);
*pn = 100;
printf("n (after): %d\n", n);
printf("Address of n: %p", (void *)pn);
return 0;
}
Output:
n (before): 64
n (after): 100
Address of n: 003AF7CC
Pointers need to POINT! A pointer is a variable that contains the adress of another variable.
int *pc;
This pointer contains some garbage value. Who knows what was in that memory before. The adress that it's pointing to could be an adress of memory that is occupied by another program. You need to assign a valid adress to a pointer if you want to change the value in that adress.
If you want to calculate sum of all the members of an array you would have to initialize the variable sum to 0 because it could contain other values.
The same is with pointers. They have to contain a valid adress of a variable if you want to modify the value.
Your program would work if you comment line *pc = 100;. You can display the adress of an uninitialized pointer but the program will crash if you try to change the value in that adress.

C Programming Simple Pointers

I'm a beginner at learning pointers. Here is my code. (Note: I'm still trying to get my head around pointers so my code won't be clean.)
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[]){
int a = 1;
char b = 's';
double c = 3.14;
int *ptra;
int *ptrb;
int *ptrc;
ptra = &a;
ptrb = &b;
ptrc = &c;
printf("I initialised int as %d and char as %c and double as %.2f\n", a, b, c);
printf("The address of A is %p and the contents of A is %d\n", ptra, *ptra);
printf("The address of B is %p and the contents of B is %c\n", ptrb, *ptrb);
printf("The address of C is %p and the contents of C is %.2f\n", ptrc, *ptrc);
I expected the following output:
I initialised int as 1 and char as s and double as 3.14
The address of A is 0xbf933094 and the contents of A is 1
The address of B is 0xbf933093 and the contents of B is s
The address of C is 0xbf933098 and the contents of C is 3.14
But instead I get this:
I initialised int as 1 and char as s and double as 3.14
The address of A is 0xbf933094 and the contents of A is 1
The address of B is 0xbf933093 and the contents of B is s
The address of C is 0xbf933098 and the contents of C is 427698.00000
Can someone help for the large number I got when printing the contents of C? Why don't I get 3.14? (The number is actually longer than that but it didn't fit into this textbox. :-))
You are declaring ptra, ptrb and ptrc as pointers to ints. But the type of a pointer is based on what it points to, so it really should be:
int *ptra;
char *ptrb;
double *ptrc;
In your specific case, your program is trying to interpret a double value through an int pointer. Since the sizes of these data types differ on your machine, some of the bits of the double get discarded and you end up with the strange number you're seeing.
This may not always happen the same way - the result of accessing something through the wrong type of pointer is not defined by the C language, but it still might compile. C programmers refer to this as undefined behaviour (a phrase you should really come to terms with if you want to learn C!).
There is also the fact that when you call printf, you need to give it variables of the type it expects from the format string. So if you give it a format string where the first placeholder is %.f, you must give it a first argument that's a double. If you don't, printf will also exhibit undefined behaviour and could do anything (the undefined behaviour may be strange output, crashing, or simply putting out the number you expect... until the worst possible moment).
Your pointers are all of type int. That is not correct. Replace those by
int *ptra;
char *ptrb;
double *ptrc;
Because your pointers are all int*. If you want it to dereference to a double, you need it to be double*. Your compiler should have warned you about incompatible pointer assignment.
You should declare pointers using the corresponding type.
int *ptra;
char *ptrb;
double *ptrc;
you need to change your pointer type to match your data type so the size will be set accordingly.
char *ptrb;
double *ptrc;
If I can just say a few words about typed pointers.
Pointers with a type (as opposed to void* pointers) know how many bytes to advance in memory. For example on 32 bit systems and integer pointer would typically advance four bytes in memory when iterating through an array containing integer values.
A char pointer (guaranteed by the C standard to be always 1 byte) would naturally advance 1 byte at a time.
Let me illustrate this with a small code snippet:
#include <stdio.h>
int main()
{
char array [] = "This is a char array.";
int* int_ptr;
char* char_ptr;
char_ptr = array; /* This is okay, we have a char array and we assign its address to a char pointer */
int_ptr = array; /* It will complain but let's go along with it */
printf("%p, %p, %p\n", array, char_ptr, int_ptr); /* They should all point to the same address in memory */
printf("%p\n", ++char_ptr); /* it will have advanced by one byte */
printf("%p\n", ++int_ptr); /* it will have advance by four bytes */
return 0;
}
I have the following output on my machine:
$ ./a.out
0xbf8b85d2, 0xbf8b85d2, 0xbf8b85d2
0xbf8b85d3
0xbf8b85d6
As you can see they have indeed advanced as we predicted. It is fairly obvious this can cause all sorts of problems when we start dereferencing our pointers and they don't match the underlying type.
Regarding void* pointers, arithmetic on them is illegal.
here the pointer ptrc is referring to the addressof varaible whose data type is integer but you are using it for double.

Very Basic C Question

Can someone check my understanding and correct me if i am wrong?
int p = 5; //create an int holding 5
int *ptr; //create a pointer that can point to an int
*ptr = &p; // not sure - does this mean that my pointer now points to memory address five, or that the memory address my pointer points at contains 5?
Sorry for the basic question - i have an assignmnet soon that requires the use of pointers and i really want to crack the basics before its set.
Almost there - change it to:
int p = 5; // create an int holding 5
int *ptr; // create a pointer that can point to an int
ptr = &p; // ptr now points at p
Your program is wrong. ptr is not initialized. Assigning to *ptr creates a memory violation most likely. You can't assign an int* (which &p is) to an int (which *ptr is).
Correct is:
ptr = &p;
Your ptr now points to the memory address that has 5 stored in it.
Also, I don't believe that code compiles. You probably want:
int p = 5; //create an int holding 5
int *ptr; //create a pointer that can point to an int
ptr = &p; // not sure - does this mean that my pointer now points to memory address five, or that the memory address my pointer points at contains 5?
A pointer is, basically, an address. Think about a pointer as an address label, and the value as the actual house. You can use the label to find the house, but the label isn't a house.
int *ptr; // declares a pointer to an int
So ptr is, essentially, a memory address. (It's possible that the C spec doesn't actually specify that it's an address, but bear with me).
int i = 5; // create a local int.
Declares an integer on the stack, and sets the value of it to 5. The address of i is somewhere in the stack space.
Let's look at one intermediate step before we go on. This probably wouldn't compile, and if it did, wouldn't actually do anything.
&i;
What this expression does is return the address of the variable i. It's the location of i in memory - the address of an integer.
And one last one...
*ptr;
Again, this probably wouldn't actually do anything, it's just an expression. But, what it does is dereference the pointer - it refers to the actual int located at the address contained in ptr.
Okay, so let's take a look at a few things that we can do.
ptr = i;
This doesn't do anything, at least anything we want to do. Probably won't compile, but I haven't checked it out. It doesn't do anything because it assigns an integer to the address of an integer. That's like sending a box through the post office to an address label - you actually want it to go to the house!
i = ptr;
Okay, this is the same thing as the last one, but in reverse. Following our analogy, this is trying to turn a house into a label!
*ptr = i;
Here we've dereferenced the pointer, and assigned the value of i to it. Dereferencing a pointer is essentially like using the label to drive to the house. Once we're there, we can do things to the actual house. This works because a dereferenced int pointer is an int, and an int is also an int.
ptr = &i;
This works too. &i basically makes a new label for the house 'i'. Since we have a pointer on both sides, we can assign one to the other. This is basically copying the address label for i to the address label called ptr.
*ptr = &i;
This doesn't make sense. We've started with two different things, and converted each into the other! Now we're trying to assign a label to a house, whereas before we were assigning a house to an address label.
You want
ptr = &p; // set ptr to point to the location holding p
Others already explained how to fix your code. For understanding, let me tell you what your wrong line does:
*ptr = &p;
*ptr dereferences the pointer, i.e., *ptr = ... assigns something into the memory slot to which ptr is pointing. Since ptr has not been initialized, it points to some unknown location in memory and *ptr = ... will probably fail with a Segmentation Fault or something similar.
Since ptr is a pointer to int, the right-hand side of *ptr = ... expects an int as well, but you pass to it the address of an int (&p), which results in a compiler warning.
I know this doesn't directly answer your immediate question (which others have already done), but I would recommend reading the section on pointers from the c-faq.
Lot's of good info.
int a=5;
declare the pointer type which is your storing
int *ptr;
assign address of variable to the pointer
ptr=&a;

Resources