Incrementing C pointers - c

I thought that if a c pointer pointing to a char array was incremented then it would point to the next element in that array. But when I tried this I found that I had to increment it twice. Trying the increment using sizeof(char) I found that adding the size of a char was too much so it had to be divided by two.
#include <stdio.h>
int main(int argc, char * argv[]){
char *pi;
int i;
pi = argv[1];
printf("%d args.\n",argc-1);
printf("input: ");
for(i=0;i<argc-1;i++){
printf("%c, ",*pi);
/*The line below increments pi by 1 char worth of bytes */
//pi+=sizeof(pi)/2;
/* An alternative to the above line is putting pi++ twice - why? */
pi++;
pi++;
}
printf("\n");
return 0;
}
Am I doing something wrong? or am I misunderstanding the method of incrementing pointers?

sizeof(char) is guaranteed to be 1, but sizeof(char*) isn't.
Nevertheless, your function only works by accident.
For example, try calling it with the following parameters:
abc defg
This will yield:
2 args.
input: a, c,
which is plain wrong. The problem is you are incrementing a pointer to the element 1 of argv instead of a pointer to argv.
Try this:
#include <stdio.h>
int main(int argc, char * argv[]){
char **pi;
int i;
pi = argv + 1;
printf("%d args.\n",argc-1);
printf("input: ");
for(i=0;i<argc-1;i++){
printf("%c, ",**pi);
pi++;
}
printf("\n");
return 0;
}
This will print the first character of every argument:
2 args.
input: a, d,

If you have a pointer ptr of type T* and you add N, then the pointer will be advanced by N * sizeof (*ptr) or equivalent N * sizeof (T) bytes. You simply forgot to dereference pi. So what you got with sizeof (pi) was the sizeof of the char*, but not the sizeof of a char. Your line was equivalent to pi+=sizeof(char*)/2; Pointers on your platform are 4 bytes big. Thus in effect you did pi+=2;. Write pi+=2 if you want to increment 2 times. Note that char has an sizeof of 1 by definition. You don't need to do sizeof (char), it is always 1.

sizeof(pi) is returning the size of (char*), which is the type of pi (a pointer, probably two, four, or eight bytes). sizeof(char) will return 1.
However, another thing to understand is that whenever you increment a pointer by a number (e.g.: pi += sizeof(char); pi++; etc.) you are incrementing the pointer by the base size anyways. So:
int *ipointer = &int_array[0];
ipointer += 2;
will actually increment ipointer by 2 times sizeof int.
Another thing you seem to be doing wrong is pointing pi at the first argument, and then looping through all the arguments. If you want to loop through the arguments, try something like this:
for (i = 1; i < argc; i++) {
pi = argv[i];
// ... do something with pi
}

Related

Why difference between pointers to two consecutive array entries is always 1, if not cast to char pointer?

What is the point of typecasting into char ? Why not typecast it in int instead ?
#include <stdio.h>
int main()
{
int arr[15];
arr[1]=5;
arr[0]=2;
int diff = (char *)&arr[1] - (char *)&arr[0];
int diff2 = &arr[1] - &arr[0];
printf("%d\n%d", diff, diff2);
return 0;
}
Pointer arithmetic is not for the weak of heart, but always this will be true:
(&arr[0]/* pointer to first element*/)
+
(1 /* "next" */)
==
(&arr[1]/* pointer to second element*/)
This is true for any type, it is part of the rules of pointer arithmetic.
So it cannot be any other than
(&arr[1]/* pointer to second element */)
-
(&arr[0]/* pointer to first element */)
==
1
which is of course exactly like
diff2 == 1
This is not changed if the result of & is cast to a pointer to the actual type of the array entries, in this case int and int*. With that +1 still means "next array entry".
On the other hand
(char *)&arr[0]
is bend to be a pointer to something different than the type of the entries of the array. It has been forced to be a pointer to a char. If you increase that by one, it has to be a pointer to the next char and
(char *)&arr[0] + N
==
(char *)&arr[1]
can only be true, if N is the number of chars between the addresses of two consecutive array entries.
So
N =
(char *)&arr[1] - (char *)&arr[0]
ensures it.
To understand this let us take a simple example:-
#include <stdio.h>
int main()
{
int arr[3]={1,2,3};
int *p=arr;
for(int i=0;i<3;i++){
printf("%d ",*p);
p++; // In this line p is an address.
//Here address is incremented by 1.
// But the logic is that 1 is an integer.
// If 1 might not be an integer then the result should not be like this.
// Same is in your case if you are storing difference of two addresses
// in an integer then it calculates the difference
// with respect to the type of address(int in your case).
}
return 0;
}
In c++ if integer is used with addresses for any operation then its calculations are totally based upon the type of address(int,void,float....).

print const char array by the result of sizeof()

#include <stdio.h>
#include <stdlib.h>
int constChars(const char* str) {
int size = sizeof(str)/sizeof(char);
printf("Size is %d.\n", size);
int i = 0;
for (i=0;i<size;i++)
printf("%c ", str[i]);
return 0;
}
int main(void) {
char a[10]={'b','c','d','e','f','f','f','f','f','f'};
constChars(a);
return 0;
}
I wrote piece of code like above, but the output result is:
Size is 8.
b c d e f f f f
I'm quite confused, why the sizeof() function gives a size of 8?
I use gcc and freebsd.
When you pass an array to a function, it gets rewritten as a pointer, where sizeof information is lost. If you did this in main instead, i.e:
char a[10]={'b','c','d','e','f','f','f','f','f','f'};
int size = sizeof(a)/sizeof(a[0]);
printf("Size is %d.\n", size);
It prints 10 as expected. But once you pass it to constChars, it prints the size of a pointer.
Str is a pointer to a char. That is typically 4 to 8 bytes. You are not getting the size of the array, but the size of the variable. The only way to know the length of the array is to pass the size in with it, or you could deliminate the array with some sort of signal value (like \0) and do some iteration.

Memcpy from a double pointer in c

I have a pointer A, which is passed into a function with address, say myfunc(&A).
In the function myfunc(char **A) {
I want to copy memory from A[2 to n] to C[2 to n] }
I tried memcpy(&c[2], &(*A)[2], 20);
I am getting the address copied into c rather than the actual info in A.
To copy memory from A[2 to n] to C[2 to n] (from question)
A is a char **, it points to a number of char *.
The 3rd char * is A[2]. You want to use the address of that element in memcpy.
So the line should be
memcpy(&c[2], &A[2], N);
where N is, according to your text, (n-2+1)*sizeof(char *). memcpy size argument ignores the type of what it copies, therefore the total size of what to be copied is to be provided. You want to copy from 2 to n, that makes n-2+1 elements. Each element is a char * which size is sizeof(char *).
-- following comment --
While not clear from the question, if you want to dereference A twice, you copy characters... like
memcpy(&c[2], &A[0][2], 20 /* 20 chars */);
C would be a char *.
memcpy(c+2, *A+2, 20) should be enough.
Here is a test program:
#include <stdio.h>
#include <string.h>
char c[10] = { 'a', 'b' };
void myfunc(char **A)
{
memcpy(c+2, *A+2, 8);
}
int
main(void)
{
char *A = "ABCDEFIJK";
printf("Before: %s\n", c);
myfunc(&A);
printf("After : %s\n", c);
return 0;
}
Run:
$ ./a.out
Before: ab
After : abCDEFIJK

Why does second printf print 0

#include<stdio.h>
int main()
{
char arr[] = "somestring";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
printf("ptr2 - ptr1 = %ld\n", ptr2 - ptr1);
printf("(int*)ptr2 - (int*) ptr1 = %ld", (int*)ptr2 - (int*)ptr1);
return 0;
}
I understand
ptr2 - ptr1
gives 3 but cannot figure out why second printf prints 0.
It's because when you substract two pointers, you get the distance between the pointer in number of elements, not in bytes.
(char*)ptr2-(char*)ptr1 // distance is 3*sizeof(char), ie 3
(int*)ptr2-(int*)ptr1 // distance is 0.75*sizeof(int), rounded to 0
EDIT: I was wrong by saying that the cast forces the pointer to be aligned
If you want to check the distance between addresses don't use (int *) or (void *), ptrdiff_t is a type able to represent the result of any valid pointer subtraction operation.
#include <stdio.h>
#include <stddef.h>
int main(void)
{
char arr[] = "somestring";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
ptrdiff_t diff = ptr2 - ptr1;
printf ("ptr2 - ptr1 = %td\n", diff);
return 0;
}
EDIT: As pointed out by #chux, use "%td" character for ptrdiff_t.
Casting a char pointer with int* would make it aligned to the 4bytes (considering int is 4 bytes here). Though ptr1 and ptr2 are 3 bytes away, casting them to int*, results in the same address -- hence the result.
This is because sizeof(int) == 4
Each char takes 1 byte. Your array of chars looks like this in memory:
[s][o][m][e][s][t][r][i][n][g][0]
When you have an array of ints, each int occupies four bytes. storing '1' and '2' conceptually looks more like this:
[0][0][0][1][0][0][0][2]
Ints must therefore be aligned to 4-byte boundaries. Your compiler is aliasing the address to the lowest integer boundary. You'll note that if you use 4 instead of 3 this works as you expected.
The reason you have to perform a subtraction to get it to do it (just passing the casted pointers to printf doesn't do it) is because printf is not strictly typed, i.e. the %ld format does not contain the information that the parameter is an int pointer.

Does sizeof(var) always work in C?

Whenever I want to read or write into a binary file using C, I do use the fread() and fwrite() functions. They need as a parameter the bytes of the datum that is being read or written so I use the sizeof() function. Now the question is:
The books says that I should declare a function like this:
fread(&variable,sizeof(TYPE_OF_VAR),quantity,file);
I've use the following statement which works most of the time but not always:
fread(&variable,sizeof(VARIABLE),quantity,file);
Why does it works sometimes but sometimes it doesn't?
Does it depends on the type of the variable (int, char, etc)?
Does it depends on the quantity of the datum that I use?
The thing to keep in mind is that sizeof is based on what the compiler knows about the type at compile time (ignoring VLA's for now). If you give it a variable, it will use the type of that variable.
So, the only time I can think of where it wouldn't work as you expect is with pointers.
basically what it boils down to is this:
int x[5];
int *y = &x[0];
int *p = malloc(sizeof(int) * 5);
sizeof(x); // == sizeof(int) * 5
sizeof(y); // == sizeof(int *)
sizeof(p); // == sizeof(int *)
This gets tricky when dealing with functions because arrays decay to pointers when passed to a function. Also note that all 3 of these are exactly equivalent:
int func(int *p);
int func(int p[5]);
int func(int p[]);
in all 3, p is a pointer, not an array.
See this Stack Overflow question for a discussion of heap vs. stack: What and where are the stack and heap.
sizeof() on heap elements, like pointers, will return the size of the pointer, not the number of elements that the pointer can store.
However, sizeof() on stack elements: arrays or const char * will return the length of the array or string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LENGTH 100
int main(int argc, char *argv[])
{
char *a = NULL;
char b[10] = "abcdefghi";
printf("sizeof(b): %zu\n", sizeof(b));
a = malloc(LENGTH + 1);
if (a) {
*(a + LENGTH) = '\0';
memset(a, ' ', LENGTH);
fprintf(stdout, "a (before memcpy):\t[%s]\n", a);
printf("sizeof(a), before: %zu\n", sizeof(a));
memcpy(a, b, sizeof(b) - 1);
fprintf(stdout, "a (after memcpy):\t[%s]\n", a);
printf("sizeof(a), after: %zu\n", sizeof(a));
free(a);
}
return EXIT_SUCCESS;
}
To compile:
$ gcc -Wall sizeofTest.c -o sizeofTest
Output:
$ ./sizeofTest
sizeof(b): 10
a (before memcpy): [ ]
sizeof(a), before: 8
a (after memcpy): [abcdefghi ]
sizeof(a), after: 8
On my platform, a char * points to a memory address that takes up eight bytes.
It will always work.
int main()
{
char a[10];
int b[10];
printf("%d %d %d %d %d %d",sizeof(char),sizeof(int), sizeof(a),sizeof(b), sizeof(a[0]), sizeof(b[0]) );
}
Try the above code. You should see (depending on compiler, mine has char as 1byte and integer as 4 bytes) 1,4,10,40,1,4
It is not different for fread or fwrite or wherever you use it.

Resources