Just for educational purpose I have written C code that gets out of array bound:
int main( int argc, char ** argv ) {
char *cp = "dabsf";
cp=cp+10;
printf("%c",*cp);
return 0;
}
I have letter n in output.
Is it possible somehow to see whole memory map and see what bytes are near cp array and find where is n?
I'm using MinGW compiler.
Here's some code to print memory out, you can use it to print memory around after any pointer you want (trying to print too much might give you an access violation, especially trying addresses before your first variable):
#include <stdio.h>
void printMemory(void *address, int rows, int cols) {
for(int r = 0, c; r < rows; ++r) {
c = 0;
printf("%8p ", (void *)(((unsigned int*)address) + (r*cols + c)));
for(; c < cols; ++c) {
printf("0x%08x ", *(((unsigned int *)address) + (r*cols + c)));
}
printf("\n");
}
}
int main(void) {
char *test = "Hello World!";
unsigned int value1 = 0xABABABAB;
unsigned int value2 = 0xDEADBEEF;
unsigned int value3 = 0xCAFEBABE;
printf("%s, %d, %d, %d\n", test, value1, value2, value3);
printMemory(test, 4, 2);
printf("\n");
printMemory(&value1, 1, 3);
return 0;
}
The output is (in my case the string was stored in a different place than the integers):
Hello World!, -1414812757, -559038737, -889275714
0x80486ad 0x6c6c6548 0x6f57206f
0x80486b5 0x21646c72 0x2c732500
0x80486bd 0x2c642520 0x2c642520
0x80486c5 0x0a642520 0x01000000
0xbf8aab50 0xabababab 0xcafebabe 0xdeadbeef
Also this works for debugging, but do not do this in real code, accessing memory addresses that aren't for your variables is undefined behavior.
To print the memory map of 10 positions from cp:
#include <stdio.h>
int main(void) {
int i;
char *cp = "dabsf";
printf("Address of 1st element of cp %p\n", cp);
for(i=1;i<=10;i++)
{
printf("Address of %c is %p\n",*(cp+i), cp+i); // cp+i is the same as &(*(cp+i))
}
return 0;
}
To get the address of any element after the array:
cp = cp + 8;
printf("Element at cp+8 is %c\n", *cp);
printf("Address of cp+8 is %p\n", cp);
Note: the output of the code just above may change in successive runs of the code.
Related
Here's the code -
#include <stdio.h>
int main()
{
char character_1 = '0';
int integer_1 = 12321;
char character_2 = '1';
char character_3 = '2';
printf("Integer occupies %zu byte(s) of space.\n",sizeof(int));
printf("Address of Integer 1: %p\n",(void*)&integer_1);
printf("\n");
printf("Character occupies %zu byte(s) of space.\n",sizeof(char));
printf("Address of Character 1: %p\n",(void*)&character_1);
printf("Address of Character 2: %p\n",(void*)&character_2);
printf("Address of Character 3: %p\n",(void*)&character_3);
printf("\n");
return 0;
}
and, the generated output -
Integer occupies 4 byte(s) of space.
Address of Integer 1: 000000000061FE18
Character occupies 1 byte(s) of space.
Address of Character 1: 000000000061FE1F
Address of Character 2: 000000000061FE17
Address of Character 3: 000000000061FE16
I want to print the addresses of all the four bytes of space occupied by the integer variable integer_1, which means print all four of these - 000000000061FE18, 000000000061FE19, 000000000061FE1A and 000000000061FE1B. How do I do it?
Is this what you are trying to do?
#include <stdio.h>
int main()
{
int integer_1 = 12321;
unsigned char* p = (unsigned char*)&integer_1;
for (int i=0; i<sizeof(int); i++){
printf("Address: %p -> Value: %02hhx\n", p+i, *(p+i));
}
return 0;
}
EDIT: As pointed out by KPCT, working with void* is indeed possible, just a bit more tedious if you are also interested in the value pointed, and not the address only.
For example, adapting my above solution to use void*, would result in something like this
#include <stdio.h>
int main()
{
int integer_1 = 12321;
void* p = (void*)&integer_1;
for (int i=0; i<sizeof(int); i++){
printf("Address: %p -> Value: %02hhx\n", p+i, *((char*) p+i));
}
return 0;
}
where you would have to go through the cast to char* anyway
You would need to cast the int pointer to a char pointer (or an int8_t pointer), then step through each of the bytes, something like this:
char *cp = (char*)&integer_1;
for (int i = 0; i < sizeof(integer_1); ++i)
printf("Address of integer_1, byte %d: %p\n",i,cp++);
I was wondering if you could help me overcome a hurdle I've run into with my C syntax. I have written the function:
binary_and_trim(char *password, unsigned *key1, unsigned *key2)
that has achieved the goal of converting a provided string into binary and trimmed off the leading zero. I have assigned my key1 and key2 pointers to the correct indexes. But then, when I return to the main function the values are all lost.
I believe that the problem is that when I pass the *key1/*key2 pointers to the function it only receives a copy of them. But, as I am new to C, I don't know how to fix it?
I created a for loop to help me test/debug.
#include <stdio.h>
#include <string.h>
void binary_and_trim(char *password, unsigned *key1, unsigned *key2);
unsigned int get_n_bits(unsigned *bits, int width, int index);
int main(int argc, const char * argv[]) {
unsigned *key1 = NULL;
unsigned *key2 = NULL;
binary_and_trim("password", key1, key2);
//This test fails with a EXC_BAD_ACCESS error
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %u key2[%d] %d\n", i, key1[i], i, (key2 + i));
}
}
void binary_and_trim(char *password, unsigned *key1, unsigned *key2){
char c;
int count = 0;
unsigned tmp;
unsigned long len = strlen(password);
unsigned trimmedbinary[len * 7];
for(int i = 0; i < len; i++){
c = *(password + i);
for( int j = 6; j >= 0; j--) {
tmp = 0;
if(c >> j & 1){
tmp = 1;
}
*(trimmedbinary + count) = tmp;
count++;
}
}
key1 = trimmedbinary;
key2 = &trimmedbinary[28];
//This test works correctly!!!
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %d key2[%d] %d\n", i, *(key1 + i), i, *(key2 + i));
}
}
I believe that the problem is that when I pass the *key1/*key2 pointers to the function it only receives a copy of them.
Yes, exactly. Pointers are just integers and integers get copied. You solve this with a pointer to a pointer, a "double pointer".
However, there is another problem. trimmedbinary is using stack/automatic memory. "Automatic" meaning it will be freed once the function exits. Once the function returns key1 and key2 will point at freed memory. trimmedbinary must be declared in heap/dynamic memory with malloc.
void binary_and_trim(char *password, unsigned int **key1, unsigned int **key2){
unsigned int *trimmedbinary = malloc(len * 7 * sizeof(unsigned int));
...
*key1 = trimmedbinary;
*key2 = &trimmedbinary[28];
for(int i = 0 ; i < 28; i++) {
printf("key1[%d] %u, key2[%d] %u\n", i, (*key1)[i], i, (*key2)[i]);
}
return;
}
And call it as binary_and_trim("password", &key1, &key2);
Update: I answered the question about how to alter the pointer value, but I have not noticed the memory issue in the code. Please refer to this answer instead.
Pointers are variables themselves. You may already know that with a pointer, you can change the value stored in the variable the pointer points to. Therefore, you need to use a pointer to a pointer to change the value (the memory address) stored in the pointer.
Change your function signature to:
void binary_and_trim(char *password, unsigned **key1, unsigned **key2)
Call with:
binary_and_trim("password", &key1, &key2);
and replace key1 and key2 to *key1 and *key2 in the function definition.
Your problem is that the variable you use to fill with your keys data trimmedbinary is allocated only for the scope of the function binary_and_trim. That said, when you print inside the function
void binary_and_trim(char *password, unsigned **key1, unsigned **key2){
...
unsigned trimmedbinary[len * 7]; // <--
...
*key1 = trimmedbinary; // <--
*key2 = &trimmedbinary[28]; // <--
//This test works correctly!!!
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %d key2[%d] %d\n", i, *(key1 + i), i, *(key2 + i));
}
}
it just works because the data your key1 pointer is trying to access is still there.
However, when you return from your function back to main, key1 and key2 still point back to the buffer you initialized inside binary_and_trim, which is no longer valid because is out of scope.
I suggest you create a buffer in main and pass it as a parameter,
int main(int argc, const char * argv[]) {
const char* password = "password";
unsigned long len = strlen(password);
unsigned buffer[len * 7]; // <-- Add buffer here
unsigned *key1 = NULL;
unsigned *key2 = NULL;
binary_and_trim(password, &key1, &key2, &buffer, len * 7);
//This test succeeds
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %u key2[%d] %d\n", i, key1[i], i, (key2 + i));
}
}
void binary_and_trim(char *password, unsigned **key1, unsigned **key2, unsigned** buffer, size_t buff_size){
char c;
int count = 0;
unsigned tmp;
...
//Use *buffer instead of trimmedbinary
//Check if buff_size matches len(password) * 7
or alternatively, make the buffer heap allocated (dont forget to free() later).
I believe that the problem is that when I pass the *key1/*key2
pointers to the function it only receives a copy of them.
Already altered in code as well.
Wow! Thank you EVERYONE! I finally got it up and running (after 4 hours of beating my head against the wall). I can't begin to say how clutch you all are.
I'm realizing I have tons to learn about the granular memory access of C (I'm used to Java). I can't wait to be an actual WIZARD like you all!
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.
How do you make 2 array strings into 1 array string, where I can print out all the 52 playing cards?
my code:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
int main() {
char deck[52];
char suits[] = {"Hearts","Diamonds","Clubs","Spades"};
char values[]= {"Ace","Two","Three","Four","Five","Six",\
"Seven","Eight","Nine","Ten","Jack",\
"Queen","King"};
int V, S, d = 0;
char string;
for ( S= 0; S <4; S++) {
for (V =0; V< 13; V++) {
string = strcat( values[V], suits[S]);
deck[d] = string;
printf("%s\n", string);//prints out all the 52 playing cards
d++;
}
}
return 0;
}
When I executed the program, the problem comes up which asks me to debug the program or close the program, where I closed the program in the end, which returns nothing. Can you please give me the answer which works?
Check the below code which fixes the issues in your code:
The problem with your code is you try to modify the actual string before printing and because of this there is a modified string in the next iteration. So just copy the values and suits to array and print it out as shown below.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
int main()
{
int i=0;
char deck[30] = "";
char suits[][30] = {"Hearts","Diamonds","Clubs","Spades"};
char values[][30]= {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack",
"Queen","King"};
int V, S;
for ( S= 0; S <13; S++)
{
for (V =0; V< 4; V++){
memset(deck,0,sizeof(deck));/* Clear the buffer before writing new value*/
strcpy( deck, values[S]);
strcat(deck,suits[V]);
printf("%s\n", deck);//prints out all the 52 playing cards
i++;
}
}
printf("Number of playing cards: %d\n",i);
return 0;
}
strcat() returns a char *, a pointer to a char, not a char.
You are not even required to even consider the return value of strcat() since the destination pointer (first argument) will now contain the concatenated string, assuming enough memory is already allocated.
So here in your code, you are trying to put the concatenated string to values[V] which could fail when memory already allocated to it becomes insufficient.
The best method would be to allocate some memory (as you did with deck[]) and set it all to zeroes. Then keep strcat()ing there.
strcat(deck, values[V]);
strcat(deck, suits[S]);
An alternative to using strcpy and strcat is to use sprintf.
#include<stdio.h>
#include<string.h>
#define NUM_SUITS 4
#define CARDS_PER_SUIT 13
#define TOTAL_CARDS (NUM_SUITS * CARDS_PER_SUIT)
int main()
{
char deck[TOTAL_CARDS][24];
char* suits[NUM_SUITS] = {"Hearts","Diamonds","Clubs","Spades"};
char* values[CARDS_PER_SUIT]= {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack",
"Queen","King"};
int s, c, i;
for(s = 0; s < NUM_SUITS; s++)
{
for(c = 0; c < CARDS_PER_SUIT; c++)
{
sprintf(deck[(s * CARDS_PER_SUIT) + c], "%s of %s", values[c], suits[s]);
}
}
for(i = 0; i < TOTAL_CARDS; i++)
{
printf("%s\n", deck[i]);
}
return 0;
}
As per my previous question (many thanks to Jonathan Leffler), I edited my code (second two blocks of code), but I ran into a rather strange problem.
The following one breaks unpredictably...
void free_array(array_info *A)
{
int i;
for(i = 0; i < (A->height); ++i)
{
printf("About to free: %x\n", A->dat_ptr[i]);//for debugging purposes
free(A->dat_ptr[i]);
printf("Freed row %i\n", i);//for debugging purposes
}
free(A->dat_ptr);
}
I initially tested create_array directly followd by free_array and it worked flawlessly with rather big arrays (10^8). However, when I do my calculations in between and then try to free() the arrays, I get an access violation exception (c00000005). When I was debugging it, I noticed that the program would execute perfectly every time if I had a breakpoint within the "free_array" loop and did every line individually. However, the compiled code wouldn't ever run past row6 of my second array on its own. I turned off all optimisations in the compiler, and I still got the error upon execution.
Additional info
typedef struct {
int height;
int width;
int bottom;//position of the bottom tube/slice boundary
unsigned int** dat_ptr;//a pointer to a 2d array
} array_info;
Where the dat_ptr is now a proper 2D pointer. The create_array function that creates the array that is to be put in the structure is (i have stripped NULL checks for readability):
int create_array(array_info *A)
{
int i;
unsigned int **array = malloc(sizeof(*array) * A->height);
for (i = 0; i < A->height; ++i)
{
array[i] = malloc(sizeof(**array) * A->width);
}
A->dat_ptr = array;
return 0;
}
This function works exactly as expected.
More Additional Info
Added after the responses of Jonathan, Chris, and rharrison33
Thank you so much, Jonathan, with every one of your posts I find out so much about programming :) I finally found the culprit. The code causing the exception was the following:
void fill_number(array_info* array, int value, int x1, int y1, int x2, int y2)//fills a rectangular part of the array with `value`
{
int i, j;
for(i=y1 ; ((i<=y2)&&(i<array->height)) ; i++)//start seeding the values by row (as in vertically)
{
for(j=x1 ; ((i<=x2)&&(i<array->width)) ; j++)//seed the values by columns (as in horizontally)
{
array->dat_ptr[i][j]=value;
}
}
}
And ((i<=x2)&&(i<=array->width)) wasn't being evaluated as I expected (Chris Dodd, you were right). I thought that it would evaluate both conditions in that order or stop if either was "FALSE", independent of their order. However, it turned out it didn't work that way and it was simply refusing to evaluate the (i<array->width) part correctly. Also, I assumed that it would trigger an exception upon trying to access memory outside of the array range, but it didn't. Anyway,
I changed the code to:
void fill_number(array_info* array, int value, int x1, int y1,
int x2, int y2)
{
int i, j;
if(y1>=array->height){ y1=array->height-1;}
if(y2>=array->height){ y1=array->height-1;}
if(x1>=array->width) { x2=array->width-1;}
if(x2>=array->width) { x2=array->width-1;}
for(i=y1 ; i<=y2 ; i++)//start seeding the values by row
{
for(j=x1 ; j<=x2 ; j++)//seed the values by column
{
array->dat_ptr[i][j]=value;
}
}
}
And now it works. The block of if()s is there because I won't be calling the function very often compared to the rest of the code and I need a visual way to remind me that the check is there.
Again, thank you so much Jonathan Leffler, Chris Dodd, and rharrison33 :)
This code, closely based on what you've gotten from me and what you wrote above, seems to be working as expected. Note the use of <inttypes.h> and PRIXPTR (and the cast to (uintptr_t)). It avoids making assumptions about the size of pointers and works equally well on 32-bit and 64-bit systems (though the %.8 means you get full 8-digit hex values on 32-bit compilations, and 12 (out of a maximum of 16) on this specific 64-bit platform).
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
typedef struct
{
int height;
int width;
int bottom;
unsigned int **dat_ptr; // Double pointer, not triple pointer
} array_info;
static void create_array(array_info *A)
{
unsigned int **array = malloc(sizeof(*array) * A->height);
printf("array (%zu) = 0x%.8" PRIXPTR "\n",
sizeof(*array) * A->height, (uintptr_t)array);
for (int i = 0; i < A->height; ++i)
{
array[i] = malloc(sizeof(**array) * A->width);
printf("array[%d] (%zu) = 0x%.8" PRIXPTR "\n",
i, sizeof(**array) * A->width, (uintptr_t)array[i]);
}
A->dat_ptr = array;
}
static void free_array(array_info *A)
{
int i;
for(i = 0; i < (A->height); ++i)
{
printf("About to free %d: 0x%.8" PRIXPTR "\n",
i, (uintptr_t)A->dat_ptr[i]);
free(A->dat_ptr[i]);
}
printf("About to free: 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
free(A->dat_ptr);
}
int main(void)
{
array_info array = { .height = 5, .width = 10, .dat_ptr = 0 };
create_array(&array);
if (array.dat_ptr == 0)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
free_array(&array);
puts("OK");
return(0);
}
Sample output
array (40) = 0x7FAFB3C03980
array[0] (40) = 0x7FAFB3C039B0
array[1] (40) = 0x7FAFB3C039E0
array[2] (40) = 0x7FAFB3C03A10
array[3] (40) = 0x7FAFB3C03A40
array[4] (40) = 0x7FAFB3C03A70
About to free 0: 0x7FAFB3C039B0
About to free 1: 0x7FAFB3C039E0
About to free 2: 0x7FAFB3C03A10
About to free 3: 0x7FAFB3C03A40
About to free 4: 0x7FAFB3C03A70
About to free: 0x7FAFB3C03980
OK
I've not got valgrind on this machine, but the addresses being allocated and freed can be eyeballed to show that there's no obvious problem there. It's coincidence that I sized the arrays such that they're all 40 bytes (on a 64-bit machine).
Follow-up Questions
What else are you doing with your data?
How big are the arrays that you're allocating?
Are you sure you're not running into arithmetic overflows?
Testing on Mac OS X 10.8.2 and the XCode version of GCC/Clang:
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Array setting and printing functions
static void init_array(array_info *A)
{
unsigned int ctr = 0;
printf("D = 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
for (int i = 0; i < A->height; i++)
{
printf("D[%d] = 0x%.8" PRIXPTR "\n",i, (uintptr_t)A->dat_ptr[i]);
for (int j = 0; j < A->width; j++)
{
printf("D[%d][%d] = 0x%.8" PRIXPTR " (%u)\n",
i, j, (uintptr_t)&A->dat_ptr[i][j], ctr);
A->dat_ptr[i][j] = ctr;
ctr += 7;
}
}
}
static void print_array(array_info *A)
{
printf("D = 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
for (int i = 0; i < A->height; i++)
{
printf("D[%d] = 0x%.8" PRIXPTR "\n",i, (uintptr_t)A->dat_ptr[i]);
for (int j = 0; j < A->width; j++)
{
printf("D[%d][%d] = 0x%.8" PRIXPTR " (%u)\n",
i, j, (uintptr_t)&A->dat_ptr[i][j], A->dat_ptr[i][j]);
}
}
}
With a call init_array(&array); in main() after the successful create_array() and a call to print_array(&array); after that, I got the expected output. It's too boring to show here.
I believe you are malloc'ing incorrectly. Try modifying your create_array function to this:
int create_array(array_info *A)
{
int i;
unsigned int **array = malloc(sizeof(unsigned int*) * A->height);
for (i = 0; i < A->height; ++i)
{
array[i] = malloc(sizeof(unsigned int) * A->width);
}
A->dat_ptr = array;
return 0;
}