I don't understand why is the last code block generating 1819043176 1870078063 6581362 0 1 2 3 4 0 6488159... These numbers are not random, but why those numbers? Thank you!
int main(void) {
int x;
int y[10];
int* p;
char* q;
int k;
char* prefix;
k = 0;
while (k < 10) {
y[k] = k;
k = k + 1;
}
x = 42;
printf("address of y are %d %d %d\n", y, y + 1, y + 9);
doit(y + 1);
p = &y[0];
printf("p is %d\n", p);
*p = 42;
p = p + 9;
printf("p is %d\n", p);
*p = 17;
q = "hello world";
p = "hello world";
k = 0;
while (k < 10) {
printf("%d ", q[k]);
k = k + 1;
}
printf("The end\n");
k = 0;
while (k < 10) {
printf("%d ", p[k]);
k = k + 1;
}
printf("The end\n");
}
doit
void doit(int p[9])
{
char* prefix = "";
int k = 0;
printf("p is %d at address %d\n", p, &p);
while (k < 10)
{
printf("%s%d", prefix, *p);
prefix = ", ";
k = k + 1;
p = p + 1;
}
printf("\n");
}
1819043176 is 6C6C6568 in hexadecimal, which is stored as the bytes 68, 65, 6c, 6c on a little-endian machine. These are the first four characters of "hello world". And so on.
Normally you are not supposed to do these things in C, the results are undefined or implementation-dependent.
If you nevertheless want to peek around in memory then better do it in a more systematical way, for example write a small utility to do a hex dump.
I'm not digging enough to give you the answer, but I do have an important suggestion: crank up your compiler's warnings. When my bash starts up, it aliases gcc to /usr/bin/gcc -Wall -Wextra -Werror so that anything I try to compile has to pass through some of GCC's harshest tests (and it treats all warnings as errors, so minor mistakes won't compile). Your code gave me an error printout a mile long (not literally). Some errors:
printf() has a special format specifier for pointers: %p. Don't use %d - that's for ints.
p is an int * (pointer to an int), "hello world" is a char *. You can assign one to another, but it's usually a bad idea, so if you really want to do it, you should use a cast to say "Hey, I meant to do this:" p = (int *) "hello world";
main() doesn't return void, it returns an int. You know this, because you declared int main(void) like a good programmer, but then we get to the end of main() and there's no return statement! How is it supposed to return an int if you don't return anything? In C++, we can skip the ending return statement, but not in C (at least, we really shouldn't, because bad things can happen).
Also, you have a pattern that you repeat often:
k = 0;
while (k < 10) {
y[k] = k;
k = k + 1;
}
Welcome to for loops:
for(k = 0; k < 10; k++) {
y[k] = k;
}
for() loops have three parts:
for(init; cond; inc)
init is run once before the loop, then the loop executes as long as cond is true, executing inc at the end of every loop. It is almost exactly equivalent to what you're doing, and is more concise.
you have p pointing to the string "hello world"
but you have defined p as a pointer to integers, so p looks like this
p[0] = 'hell'
p[1] = 'o wo'
p[2] = 'rldx'
p[3] = 'xxxx'
p[4] = 'xxxx'
p[5] = 'xxxx'
p[6] = 'xxxx'
p[7] = 'xxxx'
p[8] = 'xxxx'
p[9] = 'xxxx'
where xxxx means you have not set this memory to anything.
lets look at p[0]
h=0x68
e=0x65
l=0x6c
l=0x6c
so you have the hexidecimal number 0x6c6c6568 which you can check is 1819043176
and so on
The reason that (a) you're getting numbers printed and (b) that the numbers aren't random is because in the last code block, you're trying to print a string as decimals. After all, that's what %d expects to print - a decimal. That's not got anything to do with pointers.
You don't say what output you're expecting, but you have to chose the correct formatter to do that.
Another suggestion - the normal idiom for incrementing a variable in C and C++ is
++x;
or
x++;
to increment a value by 1 and
x += 9;
to increment it by more than 1 (obviously 9 in this case).
I think it's because you are passing a char to printf when the format string is expecting an integer. Try casting q[k] and p[k] to integers.
while (k < 10) {
printf("%d ", (int)p[k]);
k = k + 1;
}
The call to printf() is not a normal function call, it uses varargs/stdargs and in those, the function needs to unpack the correct type.
So the first number in your output, 1819043176, corresponds to 0x6C6C6568. See how the character value for the lowercase 'h' (0x68) that you were presumably expecting to see is the least significant byte in four-byte integer? This is because the varargs routines were expecting an integer-sized argument because of the %d format specifier.
This doesn't do what you think it does (I hope, maybe):
while (k < 10) {
printf("%d ", q[k]);
k = k + 1;
}
Think about what q is, what printf does, and what %d means (hint, look at the assignment of q). I would also suggest including the output of what you expect as a result because it's not obvious from the code what you're actually trying to accomplish (other than printing out pointers to ints using printf instead of ints).
Your problem is about the variable p.
it is int *, and sizeof an integer variable is 4 byte (it may change according to system and compiler) but the sizeof (char) is 1 byte
"hello world" string is 12 byte -with null-
12 byte can be defined in 3 integer.
after this line
p = "hello world";
only 3*4 memory of p will be used. (*p points array "y")
Rest of them will be null...
Related
So I'm doing pointer arithmetic homework and I need to decrement and increment pointers with this as its expected outcome. This is what I did
#include <stdio.h>
void main(void){
int d = 10;
int c = 8;
int b = 6;
int a = 4;
int *ptr; //these lines are given
printf("decrement \n");
for (ptr = &d; ptr >= &a; ptr--)
{
printf("%d \n",*ptr);
}
printf("increment \n");
for (ptr = &a; ptr <= &d; ptr++)
{
printf("%d \n",*ptr);
}
}
But the results skip 8 and 6:
decrement
10
4
increment
4
10
And so I decided to print the addresses at the beginning to help debug
printf("%p\n",(void*)&d);
printf("%p\n",(void*)&c);
printf("%p\n",(void*)&a);
printf("%p\n",(void*)&b);
But after running it, it just works
000000fc6a9ffb34
000000fc6a9ffb30
000000fc6a9ffb28
000000fc6a9ffb2c
decrement
10
8
6
4
increment
4
6
8
10
So I know that the logic works out, but it just doesn't work without printing first and I don't know why
I'm using Vscode and GCC
So I know that the logic works out, but it just doesn't work without printing first
Undefined behavior (UB), anything may happen.
int d = 10;
int a = 4;
int *ptr = &d;
ptr >= &a
ptr >= &a is undefined behavior (UB).
Order comparisons of pointers in C are UB when not part of the same array (or one after).
ptr-- is also UB as that attmepts to form the address before d. Pointer math only good within an array/object (or one after)
In your first example, you are not using variables b and c, just a and d - therefore (I suspect) the implementation is optimizing them away
In the second example, you are using variables all four variables a, b, c and d therefore they cannot be optimised away
your program have four different variables not an array of size four. So address of variables is unpredictable.
int d = 10;
int c = 8;
int b = 6;
int a = 4;
in Array memory is allocated contiguously, so use array if you want to do so.
#include<stdio.h>
int main(){
int arr[4] = {1, 2, 3, 4};
// increment
for(int i=0; i<4; i++)
printf("%d\n",*(arr + i));
// decrement
printf("-------------------------------\n");
for(int i=3; i>=0; i--)
printf("%d\n",*(arr + i));
return 0;
}
Why on compiling the below piece of code is giving runtime error?
#include<stdio.h>
int main()
{
int i;
int *p;
int a = 10;
p= &a;
printf("address of a = %x\n",p);
*(p + 0) = 5;
*(p + 1) = 6;
*(p + 2) = 7;
*(p + 3) = 8;
for(i=0; i < 4; i++)
{
printf("address = %x value = %x\n",(p+i),*(p+i));
}
return 0;
}
In this code i am assigning values to the address of variable named a after that starting from address of a the values (6,7,8) respectively are getting assigned to the next address of a consecutively.
*(p + 1) = 6;
p is an int* - meaning that when you increment it by one, it doesn't jump one byte forwards - it jumps sizeof(int) bytes forward (probably 4 bytes). If you want to assign to the bytes separately, cast the pointer to a char*:
*((char*)p + 1) = 6;
When you write code like *(p + 1) = 6; - your program is very likely to crash. Per the standard this is undefined behavior, in practice what usually really happens behind the scenes is that since p == &a and a is on the stack, p + 1 points to 4 bytes in the stack above a - which likely contains some random value like a stack canary or a return address - and you are corrupting this value.
These expressions:
*(p + 1) = 6;
*(p + 2) = 7;
*(p + 3) = 8;
Create pointers that are past the memory bounds of a which are then subsequently dereferenced. Reading memory past the bounds of an object (or even attempting to create such a pointer if it is not just past the object) triggers undefined behavior.
In this particular case it caused your program to crash, but there is no guarantee that will happen.
You should allocate that memory before accessing it. Try using malloc().
Your code should look like this:
#include<stdio.h>
int main()
{
int i;
int a = 10;
char *p= (char *)&a;
printf("address of a = %p\n",p);
for (i = 0; i < sizeof(a); ++i) {
*(p + i) = i + 5;
}
for(i = 0; i < sizeof(a); ++i) {
printf("address = %p value = %d\n", p + i, *(p + i));
}
return 0;
}
One solution is to define p as a pointer to char. Another approach is, as suggested in other answers, just cast p into a pointer to char before any arithmetic. When using pointer arithmetic, the number of bytes you "jump" is as the size of the pointed type. So, p + 1 will jump 4 bytes, in case int is 4 bytes. This is why you should use a pointer to char if you want to move one byte at a time.
In addition, your loops should run N times, where N in the number of bytes. So, my suggestion is to use sizeof.
Last thing, please note that in order to print an int you should use %d, and use %p to print pointers (i.e addresses).
I came across the following code in an MCQ quiz,
#include <stdio.h>
int main()
{
int j =2, k =4;
printf(&j["Programming"], &k["Theory"]);
k = j ^ 3;
if (k == j)
printf(&k["Practical"], "Trytosolve");
else
printf(&j["Problem creation"]);
return 0;
}
where ampersand is used in the beginning itself and outside the quotes ("") of printf statement. I am only aware of the traditional use of printf statement and its format specifiers.
I tried to run this code, and it showed no error but this warning:
format not a string literal and no format arguments
and the following output
ogrammingoblem creation (this was one of the options in multiple choices)
I tried to search for such use, but could not find. Can someone explain this use of & and square brackets?
Say we have an array a and a variable i of integral type, then a[i] is equivalent to *(a + i), i.e. we can obtain the ith element of a by decaying a into a pointer to its first element, incrementing that pointer by i and dereferencing the result. This it true because arrays occupy contiguous addresses in memory.
Now, as it turns out, i[a] is also equivalent to a[i], this is more of a "trick" that nobody (to my knowledge) would ever use in production. It's sort of intuitively justifiable that this would be the case because a[i] == *(a + i) == *(i + a) == i[a].
So then, &j["Programming"] == &(*(j + "Programming")). And because dereferencing a pointer and then taking it's address is a noop, this is j + "Programming" == "Programming" + j == "ogramming", because strings are just arrays of characters.
Same for the other branch, which is executed because 2 ^ 3 == 1 != 2.
Maybe this example program will show you the math behind the scenes:
#include <stdio.h>
int main(void)
{
int j=2, k=4;
char *p1 = "Programming";
// Print the address of j
printf("&j = %p\n", &j);
printf("\n");
printf("Pointer arithmetic\n");
// Print the address of "Programming"
printf("p1 = %p\n", p1);
// Print the value of j
printf("j = %8d\n", j);
// Print the result of the pointer computation
printf("&j[\"%s\"] = %p\n", p1, &j[p1]);
// Print the result of the equivalent pointer computation
printf("p1 + j = %p\n", p1 + j);
printf("\n");
printf("Print strings\n");
// Print "Programming" after skipping the first two letters
printf("&j[\"%s\"] = %s\n", p1, &j[p1]);
// Print "Programming" after skipping the first two letters
printf("p1 + j = %s\n", p1 + j);
return 0;
}
Output
&j = 0x7fffb3325aa8
Pointer arithmetic
p1 = 0x4006e4
j = 2
&j["Programming"] = 0x4006e6
p1 + j = 0x4006e6
Print strings
&j["Programming"] = ogramming
p1 + j = ogramming
I'm trying to pass the address of a 2D array to a function in C. I initialize the 2D array as:
const int N = 3;
char t[N][N];
I try to convert this into a char***:
char*** t_ptr = &t;
But it fails with a:
warning: initialization from incompatible pointer type
The function I want to receive the array has a prototype such as:
void f(char*** t, int N) { ... };
What am I doing wrong? Thank you.
This
char*** t_ptr = &t;
is wrong as compiler pointed because t is an two dimensional array, instead of triple pointer like char*** use pointer to an array to point to it. For e.g
char t[3][3] = { "ab","de","gh"}; /* total 3 1D array & each 1D array has 3 elements */
char (*t_ptr)[3] = t; /* t_ptr is a pointer to an array, pointing to 3 elements at a time */
And you can print t_ptr like
for(int index = 0; index < 3 ; index++) {
printf("%s\n",t_ptr[index]);
}
For reading c declarations, you can visit: https://cdecl.org/
Now using #Achal's example array:
#include <stdio.h>
#include <stdlib.h>
int main()
{
// t is a 2D array (not a VLA)
char t[3][3] =
{
{'a', 'b', '\0'},
{'d', 'e', '\0'},
{'g', 'h', '\0'}
};
printf("t is composed of 3 arrays of 3 characters each,\n");
printf("with the following addresses (on my machine):\n");
printf("--------------------------------------------------\n");
printf("%p, %p, %p\n", t[0], t[1], t[2]);
// ------------------------------------------------
// p is an array of 3 char pointers or char*
// Notice initialization
char* p[3] = {t[0], t[1], t[2]};
// following line of code will break, if no '\0' is encountered
// since %s requires a char* and a null terminator
printf("\nPrint strings using p:\n");
printf("------------------------\n");
printf("%s, %s, %s\n", *p, *(p + 1), *(p + 2));
// ------------------------------------------------
// q is a pointer to a char* or q has type char**
// Notice initialization of q (q points to p)
char** q = p;
printf("\nUsing q:\n");
printf("-----------\n");
printf("%s, %s, %s\n", *q, *(q + 1), *(q + 2));
// ---------------- printing characters individually
printf("\nIndividually:\n");
printf("---------------\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%c ",
*(*(q + i) + j)
);
}
printf("\n");
}
// -----------------------------------------------
// r is a pointer to an array of size 3 containing char
// r advances three char at a time (r doesn't know the size of t)
char (*r)[3] = t; // this is the type of t
printf("\nUsing r:\n");
printf("---------------\n");
printf("%p, %p, %p\n", *r, *(r + 1), *(r + 2));
// to extract chars
printf("%c, %c", *(*(r + 0) + 0), *(*(r + 2) + 1));
// -----------------------------------------------
return EXIT_SUCCESS;
}
Output:
t is composed of 3 arrays of 3 characters each,
with the following addresses (on my machine):
--------------------------------------------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
Print strings using p:
------------------------
ab, de, gh
Using q:
-----------
ab, de, gh
Individually:
---------------
a b
d e
Using r:
---------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
a, h
Process returned 0 (0x0) execution time : -0.000 s
Press any key to continue.
char t[N][N];
is in fact the same as
char t[N * N];
in memory. A pointer to such an array would in both cases be of type char *.
char *** is a pointer to a pointer, that is a pointer to a char, whereas char * is a pointer to a char and that's how you pass array references in C: You pass them as a pointer to the first element of that array and this first element is a char.
C cannot retain the exact type or structure of an array as soon as you pass it to functions. In memory, a char array is just a bunch of memory filled with chars and all you can pass around is a pointer to that memory. If that memory is char [] or char [][] or even char [][][] plays no role, in memory all three are a block full of chars and the function would have to explicitly know the structure in memory, otherwise all char arrays will always be char [] for a function.
I strongly discourage C beginners to ever use multidimensional arrays. Instead of
char t[N][N];
char c = t[y1][x1];
t[y2][x2] = 'X';
use
char t[N];
char c = t[y1 * N + x1];
t[y2 * N + x2] = 'X';
As that's basically what the compiler will internally do anyway.
Note that multidimensional arrays in C are not x-y, but y-x, the first value is the row, the second on the column, please see this tutorial.
Whoever disbelieves what I just said, try out this code:
int main ( ) {
char a[5][5];
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
a[y][x] = x + 10 * y;
}
}
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%02d ", a[y][x]);
}
printf("\n");
}
printf("------\n");
char * a2 = (char *)a;
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%02d ", a2[y * 5 + x]);
}
printf("\n");
}
}
You can run it online, if you like, the output is identical. Also have a look at the assembly code the compiler generates for either loop (e.g. gcc -S) and you will see it's almost identical as even in the first case the compiler uses an add and a mul instruction to access the correct memory location within the array.
sorry if this is a stupid question but I'm having an issue where all the elements of my array are being set to the last element in C. I think I'm overriding something and would like another pair of eyes. My goal is create an array of random numbers of type char. Code is below:
int main(int argc, char *argv[]) {
unsigned int seed = atoi(argv[1]);
printf("seed = %d\n", seed);
srand(seed); //NOTE: i seed random from the command line
unsigned char *p[8];
for(int i = 0; i < 8; i++){
int random_number = rand() % 255;
char random_number_string[8];
itoa(random_number, random_number_string, 10);
p[i] = random_number_string;
//below is just to check
printf("p[%d] = %s\n", i, p[i]);
}
// below i comment out irrelevant parts of the code
//unsigned char byte0[8];
//itoa( (rand() % 256), byte0, 10);
//printf("byte0 = %s\n", byte0);
//printf("Binary values: \n");
for(int n = 0; n < 8; n++){
printf("p[%d] = %s\n", n, p[n]);
//PRINTBIN((int)p[i]);
//printf("\n");
}
return 0;
The result of all this is:
seed = 1054480
p[0] = 81
p[1] = 66
p[2] = 36
p[3] = 32
p[4] = 81
p[5] = 245
p[6] = 33
p[7] = 72
p[0] = 72
p[1] = 72
p[2] = 72
p[3] = 72
p[4] = 72
p[5] = 72
p[6] = 72
p[7] = 72
I'm just wondering what I'm doing to overwite all those values. Thanks.
In your code, p is an "array" of 8 pointers to char. This means that you are storing an address location in the array p.
If you print the addresses along with the data like so -
printf("p[%d] = %s\n", i, p[i]);
printf("%d\n", p[i]);
You will notice that all the values in the array (p) are same, i.e. all the elements in the array are "same" and that is exactly what is your output shows from the second for() loop. This address is the address of the local variable random_number_string.
The first loop is printing different data as the first loop is changing the data in every iteration and after the last iteration, this address location contains the "last" value set.
Hope this clarifies the behavior that you are seeing.
Each iteration of the first cycle creates a new instance of its local char random_number_string[8]; array and then destroys it at the end. On each iteration of that cycle you are storing a pointer to the beginning of that random_number_string array in p[i]. Each pointer p[i] becomes "sour" (dangling) at the end of each i-th iteration. Thus all p[i] values end up invalid. Any attempts to access these values result in undefined behavior.
And this is exactly what your second cycle does. The behavior of your program is undefined.
Note, BTW, that it is incorrect to say that all of your array elements point to the same memory location (as some answers here do). Your array p contains invalid, indeterminate pointer values. Nothing definitive can be said about these values.
Each iteration of your first loop defines 'char random_number_string[8]' and the space for this is allocated from the stack frame. Each iteration does not increase the size of the stack frame, but is going to reuse the same stack space as the prior iteration, meaning that each time around random_number_string will be found at exactly the same address. And since you are placing the address of random_number_string into every element of your 'p' array, every element holds the same value. Whatever you place at that address will be pointed to by every element in your array.
But there's another, issue with your code. You have placed the address of an auto variable into another data structure, The problem is that stack frame that contained random_number_string is popped off the stack at the end of each iteration of your first loop, and will be reused by subsequent stack frames / code blocks.
If you know in advance the maximum size of all of these strings, then you can simply pre-allocate the lot of them with a two dimensional array. Here is the code written with this approach:
int main(int argc, char *argv[]) {
unsigned int seed = atoi(argv[1]);
printf("seed = %d\n", seed);
srand(seed); //NOTE: i seed random from the command line
unsigned char p[8][10];
for(int i = 0; i < 8; i++){
int random_number = rand() % 255;
itoa(random_number, p[i], 10);
printf("p[%d] = %s\n", i, p[i]);
}
for(int n = 0; n < 8; n++){
printf("p[%d] = %s\n", n, p[n]);
}
return 0;
}
Alternatively, you could dynamically allocate them (from the heap). Depending your program, you may need to free them when you are done with them.
int main(int argc, char *argv[]) {
unsigned int seed = atoi(argv[1]);
printf("seed = %d\n", seed);
srand(seed); //NOTE: i seed random from the command line
unsigned char *p[8];
for(int i = 0; i < 8; i++){
int random_number = rand() % 255;
p[i] = (unsigned char *)malloc(10 * sizeof(unsigned char));
itoa(random_number, p[i], 10);
printf("p[%d] = %s\n", i, p[i]);
}
for(int n = 0; n < 8; n++){
printf("p[%d] = %s\n", n, p[n]);
}
return 0;
}