Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I don't know If I can ask about C language, sorry if I can't.

I tried to understand these two codes:

C
int *pv = (int*) malloc(5 * sizeof(int));
    for(int i=0; i<5; i++) {
        pv[i] = i+1;
    }


This is a one dimensional array.
And I am confused about how malloc works and why it is also a pointer ?? Because I had more simple examples such as this one:

C
#include 
int main() {

  int x[5] = {1, 2, 3, 4, 5};
  int* ptr;

  // ptr is assigned the address of the third element
  ptr = &x[2]; 

  printf("*ptr = %d \n", *ptr);   // 3
  printf("*(ptr+1) = %d \n", *(ptr+1)); // 4
  printf("*(ptr-1) = %d", *(ptr-1));  // 2

  return 0;
}


The pointer here ptr is pointing at the address of x[2] which is written as &x[2]. So why now the pointer points at the malloc which is also a pointer?

In the Two-dimensional arrays, I saw this example :

C
int rows = 2;
    int columns = 5;
    int **matrix = (int **) malloc(rows * sizeof(int *));
    matrix[0] = (int *) malloc(rows * columns * sizeof(int));
    for (int i = 1; i < rows; i++)
        matrix[i] = matrix[0] + i * columns;


I don't understand what is written here. Why is matrix used twice? once as **matrix and one as matrix[0]? And why **matrix changed into matrix[0]?

Isn't **matrix the same as matrix[][] ??

Like in this example:

C
#include 
int main() {

  int i, x[6], sum = 0;

  printf("Enter 6 numbers: ");

  for(i = 0; i < 6; ++i) {
  // Equivalent to scanf("%d", &x[i]);
      scanf("%d", x+i);

  // Equivalent to sum += x[i]
      sum += *(x+i);
  }

  printf("Sum = %d", sum);

  return 0;
}


Here, x[0] is the same as saying *x. So matrix[][] is the same as **matrix.
So why are there two different mallroc used in matrix[0] which is weird and in **mallroc ??

Last question:

I also don't understand arrays of pointers like here:

C
#include 
 
int main()
{
 
    char* arr[3] = { "geek", "Geeks", "Geeksfor" };
 
    for (int i = 0; i < 3; i++) {
        printf("%s\n", arr[i]);
    }
 
    return 0;
}


The arrays are in char and char can only store a single character so how ? arr[0] shows geek and not just a letter "g"? And how does the *arr know what is the address of "geek" ?

This example shows:

C
#include 
 
int main()
{
    // declaring some temp variables
    int var1 = 10;
    int var2 = 20;
    int var3 = 30;
 
    // array of pointers to integers
    int* ptr_arr[3] = { &var1, &var2, &var3 };
 
    // traversing using loop
    for (int i = 0; i < 3; i++) {
        printf("Value of var%d: %d\tAddress: %p\n", i + 1, *ptr_arr[i], ptr_arr[i]);
    }
 
    return 0;
}


That in the arrays of pointer I have to put the address of the variable but in char *arr, I just put a string and not an address like above (like &var instead in char arr there is "geek" and not address of this string).

What I have tried:

I've tried to read many forums like these:

But it is so confusing.
Posted
Updated 25-Oct-23 7:23am
v2
Comments
[no name] 17-Oct-23 1:31am    
* and ** are generally "pointing", whereas [] refers to definition and internal array references. You need to adjust your frame of reference accordingly as you "read along". (A "string" is an array of characters typically terminated with a x"00" ... to answer one of your questions)

Of course you can ask about C - just because it is a fifty year old language and shows it's age badly doesn't mean you can't ask about it!
If you are learning it as your first language though, it's going to be of little help in getting you a job ... a more modern language like C# would probably be a better choice.

The first thing to know is that the name of an array is a pointer to the first element in the array - so you can use pointer syntax or array index syntax interchangeably:
C
#include <stdio.h>

int main()
    {
    printf("Hello World\n");
    int myArray[] = {1, 2, 3, 4, 5};
    int first = *myArray;
    int second = myArray[1];
    if (first == 1 && second == 2)
       {
       printf("Yes!\n");
       }
    else
       {
       printf("No!\n");
       }
    return 0;
    }
Will print "Yes!" every time.

Why is malloc a pointer? Well, it isn't - it's a function that returns a pointer, and that's different.
What malloc does is take a parameter which the number of bytes you want, and it returns a pointer to the first byte of the newly allocated memory - it doesn't know or care what you are going to do with the memory, it just allocates it on an area of memory allocated to your program called the heap. And it has a companion function called free to release that memory when you are finished with it. (You need to call free or you app starts to "leak memory" - the heap fills up with "lumps of memory" you have allocated but don't need any more.)

And a block of memory can be used however you want: as a string of characters, an integer, or an array for example (heck, you can use it as all three in different parts of your app if you want!)

Malloc returns what is called a void pointer - it's a special type that you can't use directly but you can cast it to a pointer of any type: int, int*, or even char******* if you really need it to!

Once you have a pointer, you can use it (called dereferencing), copy it, cast it - anything you need to.

In your 2D arrays example, matrix is declared as an int** - a pointer to a pointer to an integer - and malloc is asked to allocate enough space for rows pointers:
C
int **matrix = (int **) malloc(rows * sizeof(int *));
Now, C is a very old language, so it is probably producing 32bit code, which means that a pointer is also 32 bits wide - 4 bytes. So malloc is asked for a block of memory that holds rows * 4 bytes. Then next line is probably a bit confusing - it allocates a block of memory that is big enough to hold all the rows and columns of integers and assigns it to the first element in the array of pointers to integers.
Then the loop adds the pointers to each row in the array.
A better way to write that would have been:
C
int **matrix = (int **) malloc(rows * sizeof(int *));
int *arrayData = (int *) malloc(rows * columns * sizeof(int));
for (int i = 1; i < rows; i++)
   {
   matrix[i] = arrayData + i * columns;
   }
Because arrayData is a pointer to a integer, when you add a number of it it automatically includes the size of an integer to the calculation so you don't have to worry about that.

matrix[0] returns the first element in the array, and since matrix is a pointer to a pointer to an integer, it returns a pointer to an integer - the first integer in the first row.

That's why I said right at the beginning that "the name of an array is a pointer to the first element in the array" it is, and as a result *matrix and matrix[0] can be used interchangeably (but it's usually better to stick to one syntax rather than mixing them up). Equally, *(matrix + 1) and matrix[1] are equivelant and return the pointer to the second row in the array.

You need two mallocs to allocate the two memory blocks needed - one for the array of "start of rows" which is stored in matrix and one for the block of memory that will contain the row and column data itself.

In your final question, arr is not an array of chars - it's an array of pointers to charvalues. arr[0] returns a pointer to the first char in "geek", arr[1] returns a pointer to the first char in "Geeks", and so on.
So when you call printf and pass it arr[i] you aren't passing a char but a pointer to a char - so it prints the whole string, not a single character.

How does it know? The system allocates the memory for the three strings for you and copies the string literals into them when that code is executed. It then allocates enough space for the three pointers and sets them to point at the strings it just allocated, and finally sets arr to point at the first of those three pointers.

I know it's confusing, but think about it for a while, before you get a piece of paper and a pencil then pretend to be the system for a while: draw a block of memory and "allocate bits of it" you can draw an arrow to when you set a variable to point to it. You'll get the idea, but it may take a while and a fair amount of "rubbing out"!

This is why I said that C is a poor starter language: In more modern languages (like C# for example, though there are many) you don't have to worry about pointers, they all go on behind the scenes and you just deal with the variables and their content.
 
Share this answer
 
Comments
Member 16116753 17-Oct-23 18:05pm    
Hello !

I've choosed C language because of microcontrollers and microprocessors and some stuff from VHDL. That's why I've decided to learn it (although I am not a great programmer because I often use "if else" statements ...), I know there are also objective programming like C+ and other languages but I don't get it at all ...

Comming back to earth I think I somehow understand it ? I need sometime but I've decided to leave a comment to not abandon this question and maybe hope for reply if I comeback asking here in this post ;>

Pointers are the hardest part for me because reading them and trying to understand them sometimes makes me sick because I don't know what is pointing to what and why there are pointers that have a lot of stars "***" etc. That's why I am reading from many websites as possible.

I'm still struggeling with this char *arr example because I still don't get it how it gets the content I saw a non pointer example with string

// C Program to print Array of strings without array of pointers
#include <stdio.h>
int main()
{
    char str[3][10] = { "Geek", "Geeks", "Geekfor" };
 
    printf("String array Elements are:\n");
 
    for (int i = 0; i < 3; i++) {
        printf("%s\n", str[i]);
    }
 
    return 0;
}


but I don't get it how the %s know that he has to go through every element.

I have here a website https://www.geeksforgeeks.org/array-of-pointers-in-c/ It showed the addres of first letter and it was 2000 "g" so another letter is 2001 "f" and I guess 2002 "g" ?? ok so now another string starts poiting at 2004 which will be leter "g" 2005 "e", 2006 "e" and 2007 "k"

But there is a problem because there is a 5th row which addres is 2016 it should be "G" but the 4th row last letter as I counter is also 2016. Error ?

Also how does the array know that from typing 'geek' it will give the address ? Like in my example the *ptr had in his {} only &var which where the addresses of the variable. So how ?
Maxim Kartavenkov 18-Oct-23 5:33am    
In the example you mentioned they showing the addresses for the x86 platform there size of pointer is 4 bytes long
as you have an array of pointers to another array so you at the top have an array of pointers.
Size of each pointer is the 4 bytes so if the address of the first element is 2000 then next array element is 2004
As you have pointer type then at the address of 2000 you contains the pointer to your string but not the actual string data.
This pointer is the address of the first character in the string. So at the address 2000 - first array element may be stored the value 2020 address of the string.
So at the 2020 you will have 'g' at 2021 - 'f' 2022 - 'g' and at 2023 - '\0'
Member 16116753 18-Oct-23 6:57am    
Pointer that is 4 byte long ? Weird. I thought that pointers have usually 8 bytes like char * but this question is for another post
Maxim Kartavenkov 18-Oct-23 7:19am    
on x86 platform pointer 4 bytes long, on x64 platform it is 8 bytes
Member 16116753 18-Oct-23 7:33am    
I don't quite get it so I asked in another question because I struggel understanding how these bytes works. In my next question I've shown from char *arr that the address of arr is one byte per character but &arr is 8 byte per I guess pointer ? Which doesn't make sense because normal array is also somekind of a pointer because the address of array is a pointer to it's content let's say value[2] = {1, 2}. So the address &value[0] is a pointer to it's content value[0]. In char *arr I have double pointer which are &arr and arr, but it's value *arr should be one byte ? but instead arr is one byte from every step like 1 string has 5 characters so arr+0 and arr+1 have 6 bytes difference but the pointer is 8 bytes ....
malloc (see, for instance: malloc - cppreference.com[^]) allocates on the heap, while, in the 'simpler example', the array is allocated on the stack.
If you need a bidimensional dynamically allocated array (specifically a jagged array[^]) then you have to use malloc twice.

A good C book could help you to fill the gaps.
 
Share this answer
 
This is the generic understanding of the pointers itself.
The pointer means that it contains an address of the memory.
In you example you have an array:
int x[5] = {1, 2, 3, 4, 5};
So the x is the pointer to the array in memory with the 5 integer elements.
To access the value of an array element you can use the brackets: x[0], x[1] but to get address of this element you should use ampersand - getting reference to the value, which is done in your example: ptr = &x[2];
So the x is the pointer to the first element and the ptr is the pointer to the third element.
If array typed then incrementing pointer moves it to the next element and decrement moves to previous element. So in your example: ptr + 1 - next element which is equals to &pts[1] and is same time its the &x[3]. And the ptr - 1 is the previous element &pts[-1] or &x[1].
To get the value of the typed pointer used the "*" character so the *ptr gives you the value of the data with type of int from the memory which pointed by the ptr which is equals to ptr[0].
You should understand that the if you have two pointer to the same memory. So, if you set value at one pointer then you have same on another as they are point to the same address. Back to your example: *ptr = 10; printf("%d",x[2]); write the "10" to the output as ptr has the same address as the x[2], and in same time x[2] = 10; printf("%d",*p) gives you the same result.
That all you should keep in mind with the multidimensional arrays: you have array with the pointers. And you should work with them in the same way.
int matrix[3][3]; // array
int** pp = (int**)matrix; // pp point to the same array

Back to your example you have the pointer to the array of pointers: matrix in the first malloc you allocate the memory for this array as it allocated dynamically. And the second malloc allocates the memory for the actual data. You can allocate the data one time for the whole array - including memory for the data, but then you just should setup it properly based on your dimension but this be more complex for you as it require types casting:
int ** matrix = (int**)malloc(rows * sizeof(int*)+ rows * columns * sizeof(int));
matrix[0] = ((int*)matrix) + rows * sizeof(int*);

With the characters array is the same you have array of pointers to the character. char * arr[3]; So you have not the single character but the zero-ending string. And the printf function in your code with the "%s" manage display such string.
In your next example you have the reference operator to the variables for filling array of the pointers.
Making array of characters you can made easy from the example:
char * var1 = "geek";
char var2[] = "Geeks";
char var3[9] = "Geeksfor";
char* ptr_arr[3] = { &var1, &var2, &var3 };

Seems that's all of your questions.
Regards,
Maxim.
 
Share this answer
 
v2
Comments
k5054 17-Oct-23 16:10pm    
int matrix[3][3] defines a block of memory to hold 9 ints. The declaration int **ptr; defines a pointer that points to a pointer to int. These are not the same thing! E.G.
int mat[3][3] = { {0,1,2},{3,4,5},{6,7,8} };
int **ptr = (int **)&mat;
printf("%d\n", mat[1][1]); /* prints "4" */
printf("%d\n", ptr[1][1]); /* seg faults! */ 


To get a pointer to a row of the mat, you need to use int (*p)[3] = mat; Now you can access the elements of mat through the pointer ptr as you would expect: printf("%d\n", ptr[1][1]);

I think this is a fairly common mistake. I know I've made the mistake of thinking a double-pointer e.g. **ptr is equivalent to a pointer into a 2D array, but it is not.
Maxim Kartavenkov 17-Oct-23 16:59pm    
Good point - that is correct for static defined array, but nobody saying that you can access all elements of the fixed multidimensional array with casting to int** in same way - this way you are pointing to the first line only. Accessing all elements this way is possible if the memory allocate as the single block and/or without alignment - for example int** will work on x86 platform, as on x64 you have different pointer size, this way you can access the ptr as one dimension array from 0 to 9.
In your case we don't know the array bounds for the resulted ptr value and the alignment for the element or for the row will be different.
Btw there is a bug in your code: int **ptr = (int **)&mat; should be int **ptr = (int **)mat;
Maxim Kartavenkov 18-Oct-23 5:10am    
Just remember that I also face such thing long time ago. But this works fine with own allocated arrays as alignment will be same in that case:
int mat[3][3] = { {0,1,2},{3,4,5},{6,7,8} };
int rows = 3;
int cols = 3;
int ** matrix = (int**)malloc(rows * sizeof(int*)+ rows * cols * sizeof(int));
matrix[0] = (int*)(((unsigned char*)matrix) + rows * sizeof(int*));
for (int i = 1; i < rows; i++)
    matrix[i] = (int*)((unsigned char*)matrix[0] + i * cols * sizeof(int));
for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
        matrix[i][j] = mat[i][j];
int **ptr = (int **)matrix;
printf("%d\n", mat[1][1]);
printf("%d\n", matrix[1][1]);
printf("%d\n", ptr[1][1]);
Member 16116753 17-Oct-23 17:57pm    
Hello !

I do have a question though with this char *array. Because I still don't get it, why it is zero ending string. Ok first of all (to not mix a lot of stuff), why then the arrays is set to be a char ? Each element is 1 byte let's say the first address of char *array is 100 and moving by 1 "array + 1" then I have address 101. I guess ? So how is it possible that
printf("%s\n", arr[i]);
it will read the rest of the characters ? Because typing arr[i] I get to the address of a pointed character, how the rest of the characters are stored ? If I write *arr[i] I will get the first letter of a string not full string, if I write arr[0][1] then I think I should get the first letter and typing arr[0][2] I should get another but how do I know if another letter is one byte apart from the first letter.

The great example was also here :

<pre> int* arr[5];
    for(int i=0; i<5; i++) {
        arr[i] = (int*)malloc(sizeof(int));
        *arr[i] = i;
    }


Which if I type arr[5][1] then I should get I guess another value but there are no additional elements.

It's so messy ...

PS.

// C Program to print Array of strings without array of pointers
#include <stdio.h>
int main()
{
    char str[3][10] = { "Geek", "Geeks", "Geekfor" };
 
    printf("String array Elements are:\n");
 
    for (int i = 0; i < 3; i++) {
        printf("%s\n", str[i]);
    }
 
    return 0;
}



but I don't get it how the %s know that he has to go through every element.

I have here a website https://www.geeksforgeeks.org/array-of-pointers-in-c/ It showed the addres of first letter and it was 2000 "g" so another letter is 2001 "f" and I guess 2002 "g" ?? ok so now another string starts poiting at 2004 which will be leter "g" 2005 "e", 2006 "e" and 2007 "k"

But there is a problem because there is a 5th row which addres is 2016 it should be "G" but the 4th row last letter as I counter is also 2016. Error ?

Also how does the array know that from typing 'geek' it will give the address ? Like in my example the *ptr had in his {} only &var which where the addresses of the variable. So how ?
Maxim Kartavenkov 18-Oct-23 4:34am    
The array of characters its the string
you can define it as char text[100] - this array can contains up to 100 characters
most of the common library strings functions operates with the zero-ending strings, this means that the last character in the string is the '\0'
so our string may have 99 characters as we should keep one character.
In the string you can access the each character by the index.
In the example we iterate trough all characters in the string and display them.
char text[100] = "Some text";
for (int i = 0; i <  strlen(text); i++) { printf("%c\n",text[i]); } 

As you can see we uses the "%c" in format string which display the single character.
Now compare it to the next code.
char text[100] = "Some text";
for (int i = 0; i <  strlen(text); i++) { printf("%s\n",&text[i]); } 

Here we are using the "%s" format which output the zero-ending string.
As this format expect not single character we specify ampersand to get reference of the character.
In your example you have array of array of characters or array of strings:
char* arr[3] = { "geek", "Geeks", "Geeksfor" };
See that you have type of array "char *" - this means that pointer to character.
with such initialization it point to zero ending string which is hardcoded.
in your case arr[0] - character pointer to the "geek\0", arr[1] - "Geeks\0"
The '\0' character added automatically with such definition.
As in your example it uses the "%s" format - it display whole string.
To display single character you can use the "%c" format but it need you you pass character instead of array of characters, so you should use the array index or "*" to get data from the address
char* arr[3] = { "geek", "Geeks", "Geeksfor" };
// display entire string
for (int i = 0; i <  3; i++) { printf("%s\n",arr[i]); } 
// displays the first character
for (int i = 0; i <  3; i++) { printf("%c\n",*arr[i]); } 
// also displays first character
for (int i = 0; i <  3; i++) { printf("%c\n",arr[i][0]); } 
// displays second character
for (int i = 0; i <  3; i++) { printf("%c\n",arr[i][1]); } 
// Compare that with the previous output
for (int i = 0; i < 3; i++) { 
    printf("-----\n");
    for (int j = 0; j < strlen(arr[i]); j++)
          printf("%c\n", arr[i][j]);
}

In next example you allocate memory for the single element in the second dimension of the array.
so accessing arr[0][1] - cause crash:
int* arr[5];
for(int i=0; i<5; i++) {
   arr[i] = (int*)malloc(sizeof(int));
   *arr[i] = i;
}

In that example you have array of the pointers to int with the 5 elements
you initialize each pointer by allocating memory with size of int - which is single element.
But you can access that one element with arr[0..4][0].
To access more elements you should allocate larger memory
int nb_elements = 20;
arr[0] = (int*)malloc(sizeof(int) * nb_elements);
for (int i = 0; i < nb_elements; i++) arr[0][i] = i;

The arr[5][1] same as arr[5] is out of bound of the array so you got the crash as index should be in range from 0 to 4 inclusive.
The operators "*" and "&"- used with typed pointers or values only.
The operator "*" used to retrieve value at the specified typed pointer.
The operator "&" used to retrieve address of the specified typed variable.
// Variable in stack
int a = 20;
// Pointer o that variable
int * p = &a;
printf("%d\n",*p); // display the value
printf("%d\n",p[0]); // display the value
int ** pp = &p; // Pointer to pointer - now "pp" contains address of the variable "p"
// to access the variable "a" we should use the two times "*" 
printf("%d\n",*(*pp)); // display the value
printf("%d\n",(*pp)[0]); // display the value
printf("%d\n",pp[0][0]); // display the value
printf("%d\n",*(pp[0])); // display the value


Regards,
Maxim
malloc only allocated some memory block and it is your task to deal with that memory and use some typed pointer to work with it.

For complex solution I recommend the usage of structs which give you (and the compiler) some help how to deal with that memory.

Always a pointer is only a pointer to some memory and NOT the memory to which it is pointing.

Try to work with C++ to get better support for new features and spend some times with tutorial and its examples. It will avoid a lot of headaches.
 
Share this answer
 
Comments
0x01AA 17-Oct-23 14:10pm    
At first I thought what a useless answer, I'll vote something between 1...3.

But after reading it again (and again) and especally the statement 'Always a pointer is only a pointer to some memory and NOT the memory to which it is pointing.' made me give it a 5 ;)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900