free pointer passed to another function in C - c

I want to free a pointer in another function to save lines in my actual function, but when i use this self-written function:
void free_func(char *ptr1, char *ptr2)
{
if (ptr1)
{
free(ptr1);
ptr1 = NULL;
}
if (ptr2)
{
free(ptr2);
ptr2 = NULL;
}
}
it doesn't free my pointer.
This is my main function where i call my free_function:
int main(void)
{
char *test;
test = (char *)calloc(5, sizeof(char));
test[0] = 'h';
test[1] = 'e';
test[2] = 'y';
test[3] = '\0';
printf("test before: %s\n", test);
//free_func(test, 0, 0);
free(test);
test = NULL;
printf("test after: %s\n", test);
return(0);
}
This will give me the expected output:
test before: hey
test after: (null)
But if i comment the line where i free and use NULL, and uncomment my free_func, i will get this output:
test before: hey
test after: hey
My question now: why does my self written free function does something different, then the actual same lines in my main function?

it doesn't free my pointer.
You are mistaken. It does free the memory to which your pointer points (i.e. the memory returned be calloc).
There's no way to check this. Well, short of using something like -fsanitize=address or valgrind to check for memory leaks.
why does my self written free function does something different, then the actual same lines in my main function?
Actually, they do exactly the same thing. They free the memory, then set the variable to NULL.
The only difference is that the variable you print (test) isn't the variable you set to NULL (ptr1) when using the function. If you want the function to change the variable in the caller, you will need to give it the address the variable.
void free_and_set_null( void **pp ) {
free( *pp );
*pp = NULL;
}
int main( void ) {
char *p = malloc( 1 );
// ...
free_and_set_null( &p );
}
At least, that's the normal solution. It doesn't quite work here since we want to accept any kind of pointer. On a x86/x86-64, all pointers are the same size, and NULL is the same for every type of pointer. But that's not the case everywhere. As such, the above code violates the standard and warns.
Here, a macro could be used.
#ifdef _DEBUG
#define SAFE_FREE( p ) do{ free( p ); p = NULL; } while 0
#else
#define SAFE_FREE( p ) free( p )
#endif
int main( void ) {
char *p = malloc( 1 );
// ...
SAFE_FREE( p );
}

Related

Problem with free in language C which doesn't work

I wrote this program and I want to free a structure myStruct but it doesn't compile it says:
free():double free detected in tcache2
Can you help me please ?
#include <stdio.h>
#include <stdlib.h>
typedef struct myStruct {
char* chaine;
struct myStruct* next;
} mystruct;
void supprimer(myStruct* D) {
free(D->chaine);
free(D);
}
int main()
{
myStruct* D = malloc(sizeof(myStruct));
D->next = NULL;
char* chaine = malloc(sizeof(char)*10);
chaine = "ouii";
D->chaine = chaine;
supprimer(D);
printf("Hello World");
return 0;
}
I tried to run the main with creating a new structure and deleting it but it doesn't work.
chaine = "ouii"; is wrong. That does not copy “ouii” into the memory pointed to by chaine, it sets the pointer chaine to point to the array created for the string literal "ouii". That address should not be passed to free.
Change chaine = "ouii"; to strcpy(chaine, "ouii");.
char* chaine = malloc(sizeof(char)*10);
chaine = "ouii";
The second statement changes what chaine was originally pointing to (i.e. a pointer to a region of heap memory returned by malloc), such that it now points to the string literal ouii. Now you've lost access to the original memory returned by malloc (have leaked memory), and are trying to free memory not returned by one of the memory allocation functions. Hence the warning.
Possible fix:
Use the standard strcpy to copy the strings.
strcpy (chaine, "ouii");
And add #include <string.h> to the list of headers.
Aside: malloc returns NULL on failure. You should check if the pointer is valid before accessing it. It also sets errno to ENOMEM on POSIX-compliant systems. Here's one way I prefer to handle it in main ():
#include <errno.h>
errno = 0;
char *chaine = malloc (10); /* sizeof (char) is defined to be 1 */
if (!chaine) {
errno = ENOMEM;
perror ("malloc");
return EXIT_FAILURE;
}
See also: How do I modify a char** in another function
This code snippet
char* chaine = malloc(sizeof(char)*10);
chaine = "ouii";
results in a memory leak.
At first a memory was allocated dynamically and its address was assigned to the pointer chaine
char* chaine = malloc(sizeof(char)*10);
and then the pointer was reassigned with the address of the first character of the string literal "ouii"
chaine = "ouii";
So the address of the dynamically allocated memory was lost.
Instead of this assignment
chaine = "ouii";
you need to copy characters of the string literal into the dynamically allocated memory using standard string function strcpy declared in the header <string.h>. For example
#include <string.h>
//...
char* chaine = malloc(sizeof(char)*10);
strcpy( chaine, "ouii" );
Pay attention to that this function
void supprimer(myStruct* D) {
free(D->chaine);
free(D);
}
makes the pointer D declared in main
myStruct* D = malloc(sizeof(myStruct));
invalid.
It is better to pass the pointer to the function by reference.
In C passing by reference means passing an object (including pointers) indirectly through a pointer to it. Thus dereferencing the pointer you will have a direct access to the object pointed to by the pointer and can change it.
Also as it seems you want to define a singly linked list then the function can look the following way
void supprimer( myStruct **D )
{
while ( *D != NULL )
{
myStruct *current = *D;
*D = ( *D )->next;
free( current->chaine );
free( current );
}
}
And the function is called like
supprimer( &D );
In this case after calling the function the pointer D defined in main will be equal to NULL.
Pay attention to that you should check whether memory was allocated successfully to avoid undefined behavior.
Here is a demonstration program that shows how your list could be implemented.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct myStruct
{
char *chaine;
struct myStruct *next;
} mystruct;
int push ( myStruct **D, const char *chaine )
{
myStruct *current = malloc( sizeof( *current ) );
int success = current != NULL;
if (success)
{
current->chaine = malloc( strlen( chaine ) + 1 );
success = current->chaine != NULL;
if (success)
{
strcpy( current->chaine, chaine );
current->next = *D;
*D = current;
}
else
{
free( current );
}
}
return success;
}
void supprimer( myStruct **D )
{
while (*D != NULL)
{
myStruct *current = *D;
*D = ( *D )->next;
free( current->chaine );
free( current );
}
}
void output( const myStruct *D )
{
for ( const myStruct *current = D; current != NULL; current = current->next )
{
printf( "\"%s\" -> ", current->chaine );
}
puts( "null" );
}
int main( void )
{
myStruct *D = NULL;
push( &D, "World" );
push( &D, "Hello" );
output( D );
supprimer( &D );
}
The program output is
"Hello" -> "Word" -> null

Pointer is "passed by value"?

After calling f() on ptr, I expect it to point to a single byte with value of A.
But instead ptr is copied by value and it is only available in the f function(?)
What am I doing wrong?
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
Thanks!
Yes, it's passed by value. If you want the changes you make to the pointer to be visible at the call site, you need to pass a pointer to the pointer.
Example:
#include <stdlib.h>
#include <stdio.h>
void f(char **ptr) { // pointer to the pointer
*ptr = malloc(1);
if(*ptr) // precaution if malloc should fail
**ptr = 'A';
}
int main(void) {
char *ptr;
f(&ptr); // take the address of `ptr`
if(ptr) // precaution again
printf("%c\n", *ptr); // now fine
free(ptr); // without this, you have a memory leak
}
Or, f() could simply return the pointer.
Form the habit of testing return values.
#include <stdio.h>
#include <stdlib.h>
char *f(void) {
char *ptr = malloc(1);
if( ptr != NULL )
*ptr = 'A';
return ptr;
}
int main() {
char *ptr = f();
if( ptr != NULL )
printf( "%c\n", *ptr );
free( ptr );
}
You might even be able to save some code if you write main() like this:
int main() {
char *ptr;
if( ( ptr = f() ) != NULL )
printf( "%c\n", *ptr ), free( ptr ), ptr = NULL;
/* more code that will see ptr as NULL */
}
And, that leads to this (being inefficient but valid):
int main() {
for( char *ptr = f(); ptr; free( ptr ), ptr = NULL )
printf( "%c\n", *ptr );
}
You are passing the pointer ptr to the function f() by value.
This essentially means that the pointer variable you passed to f() will be copied locally inside f().
Any changes made to the local copy will only affect the local copy and not the original variable you passed to f().
When a variable is passed by value, it's copy can be referenced by whatever the function argument is called.
In your case, the pointer you pass to f() has been copied inside f() and the local copy can be referenced by ptr, since that is the argument name in:
void f(char *ptr)
Now you know how pass by value works you may now understand why your code is erroneous.
In the code:
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
You modify a local copy of what you passed into f() called ptr. And since it is local, it has something called automatic storage duration.
Automatic storage duration essentially means that after the function ends, all local variables will cease to exist and the memory they occupy will be freed. This means your code actually causes a memory leak because the pointer to the memory you allocated is lost.
Solution:
In order to achieve what you want and to modify the pointer called ptr declared in main() you must pass the address of the pointer you want to modify.
This would look like this:
void f(char **ptr)
{
*ptr = malloc(sizeof(char));
if (*ptr == NULL)
{
fprintf(stderr, "malloc fail");
return;
}
**ptr = 'A';
}
int main()
{
char *ptr;
f(&ptr);
printf("%c\n", *ptr);
return 0;
}
Output:
A
Function parameters are its local variables. Changing a local variable has no effect on the argument expression.
You can imagine the function definition and its call the following way
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
void f( /*char* p */ ) {
char *p = ptr;
p = (char*) malloc(1);
*p = 'A';
}
That is the function parameter p (I renamed it to distinguish the parameter and argument in the function call) is initialized by the value of the argument expression and within the function the local variable p that occupies its own extent of memory is changed.
To change the original pointer you need to pass it to the function by reference. In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer you get a direct access to the original object.
So the function in your program should be defined the following way
void f(char **ptr) {
*ptr = (char*) malloc(1);
**ptr = 'A';
}
and called like
f( &ptr );
you are passing a address of ptr so this will be copied to the funktion f(),
a smiple solution can be: you make the f(...) return a char* and used in the main: ptr = f(ptr);
Alternatively, you can allocate the memory for ptr where you declare it:
void f(char* ptr) {
*ptr = 'A';
}
int main() {
char* ptr = malloc(1);
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
free(ptr);
}

I can't figure out how to use double pointers

I'm trying to use dynamic memory allocation but I can't figure out pointers.
I got the first part down.
void addtext(char **wordarray)
{
char word[N];
char endword[N] = "end";
int i=0;
int words=0;
while (scanf("%19s", word), strcmp(word,endword))
{
words++;
wordarray = realloc(wordarray, words*sizeof(char *));
wordarray[words-1] = malloc (N*sizeof(char));
strcpy(wordarray[words-1], word);
}
for (i=0; i<words; i++)
printf("%s\n", wordarray[i]);
return ;
}
But I'm having trouble when I try to call the same array in a different function.
void savetext(char **wordarray)
{
FILE *savedtext;
int i=0;
savedtext = fopen("Saved Text.txt","wt");
while(wordarray[i][0]!= '\0')
{
fputs(wordarray[i++],savedtext);
fputs(" ",savedtext);
}
return ;
}
My main function looks something like this:
int main (void)
{
char **wordarray;
addtext(wordarray);
savetext(wordarray);
return 0;
}
The second part of the code is obviously wrong, but I'm not sure how to exactly how to call those functions. My previous program didn't use any memory allocation so I didn't bother with pointers.I'm really new to c so any help would be appreciated.
Oh boy. Well, you have two big problems.
First, you never allocated the first wordarray. At the very least malloc it once:
char **wordarray = malloc(1);
Or even better, use malloc instead of realloc the first time (and initialize wordarray with 0!):
wordarray = wordarray ? realloc(wordarray, words * sizeof(char *))
: malloc(words * sizeof(char *));
Second, your addtext function is receiving a copy of this array, and doing stuff with it. Whatever the stuff is, it won't be saved in your wordarray outside, in main. What you need to do is pass a pointer to the array in your function, and edit the main object through that:
void addtext(char ***wordarray)
{
// ...
}
And lastly, you have some very big performance problems, allocating buffers so often. Use a proper growing vector implementation, or if you insist on writing your own at the very least grow it by doubling the size, or even better count the words and allocate the correct size.
Also your end string is arbitrarily allocated of length N, whatever that is. You don't need that, you already know the length. In fact the string is already in the read-only section of your binary, simply get a pointer to it:
const char *endword = "end";
Perhaps refactor your program to make the string creation its own function, and for symmetry, return storage of the string as its own function.
const int STRING_SIZE = 80;
void createString(char ** strPtr, int stringSize);
void freeString(char * strPtr);
int main(int argc, char ** argv) {
char * strValue = NULL;
createString(&strValue, STRING_SIZE);
// ... do stuff ...
freeString(strValue);
}
//
// end of main
//
void createString(char ** strPtr, int stringSize) {
//
// uses pass-by-reference to return *strPtr with allocated storage
//
*strPtr = (char *) calloc(stringSize, sizeof(char));
}
void freeString(char * strPtr) {
if(strPtr == NULL) return;
free(strPtr);
strPtr = NULL;
}
For starters the program has undefined behavior at least because the pointer wordarray was not initialized and has an indeterminate value
char **wordarray;
and this indeterminate value is used in a call of the function realloc in the function addtext
wordarray = realloc(wordarray, words*sizeof(char *));
Moreover the pointer is passed to the function addtext by value. That is the function deals with a copy of the value of the pointer. So changing the copy does not influence on the value stored in the original pointer. The original pointer in main will stay unchanged.
You need to pass the pointer by reference through a pointer to it.
Another problem of the function is that the number of stored strings will not be known outside the function addtext. You need at least append the array with a null pointer that will be used as a sentinel value.
Also this condition in the while loop within the function savetext
while(wordarray[i][0]!= '\0')
does not make a sense because within the function addtext you stop entering strings when the user will enter the string "end".
while (scanf("%19s", word), strcmp(word,endword))
^^^^^^^^^^^^^^^^^^^^
So it is not necessary that the preceding entered string is an empty string.
Here is a demonstrative program that shows how for example the function addtext can be declared and defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
size_t addtext( char ***wordarray )
{
char word[N];
const char *sentinel = "end";
size_t n = 0;
int success = 1;
while ( success && scanf( "%19s", word ) == 1 && strcmp( word, sentinel ) != 0 )
{
char **tmp = realloc( *wordarray, ( n + 1 ) * sizeof( char * ) );
success = tmp != NULL;
if ( success )
{
++n;
*wordarray = tmp;
( * wordarray )[n-1] = malloc( strlen( word ) + 1 );
if ( ( *wordarray )[n-1] ) strcpy( ( *wordarray )[n-1], word );
}
}
return n;
}
int main(void)
{
char **wordarray = NULL;
size_t n = addtext( &wordarray );
for ( size_t i = 0; i < n; i++ )
{
if ( wordarray[i] != NULL ) puts( wordarray[i] );
}
for ( size_t i = 0; i < n; i++ )
{
free( wordarray[i] );
}
free( wordarray );
return 0;
}
If to enter the following sequence of strings
one
two
three
end
then the program output will be
one
two
three
Correspondingly the declaration of the function savetext should be changed. There is not sense in this case to pass the pointer wordarray to the function by reference because the pointer itself is not changed within the function. Also you need to pass the number of elements in the allocated array, So the function declaration can look at least like
void savetext( char **wordarray, size_t n );

C - proper syntax for pointer

I call a function global var as follow:
char *Pointer;
I then pass it into function:
char *MyChar = DoSomething (&Pointer);
which is defined as:
char *DoSomething (char *Destination)
{
free (*Destination);
//re-allocate memory
Destination = malloc (some number);
//then do something...
//finally
return Destination;
}
it only works if I use (*Destination) instead of (Destination). can someone tell me if that is correct? I still do not understand why it does not take (Destination).
It is correct, Destination is already declared as a pointer, so you pass the address of Destination in DoSomething(&Destination), that is like a pointer to pointer, then you need to dereference Destination inside DoSomething() function, for which the indirection operator * works.
But the right way, is not to pass the address of the pointer, but the pointer instead like in
DoSomething(Destination);
now, since you want to malloc Destination inside the function, you should the do this
char * DoSomething( char **Destination )
{
// free( Destination ); why?
//re-allocate memory
*Destination = malloc( some number );
//then do something...
//finally
return *Destination;
}
this is a demonstration of how you can use pointers
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *copyString(const char *const source)
{
char *result;
int length;
length = strlen(source);
result = malloc(length + 1);
if (result == NULL)
return NULL;
strcpy(result, source);
printf("The address of result is : %p\n", result);
printf("The content of result is : %s\n", result);
printf("The first character of result is # %p\n", &result[0]);
return result;
}
int main()
{
char *string = copyString("This is an example");
printf("\n");
printf("The address of string is : %p\n", string);
printf("The content of string is : %s\n", string);
printf("The first character of string is # %p\n", &string[0]);
/* we used string for the previous demonstration, now we can free it */
free(string);
return 0;
}
if you execute the previous program, you will see that the pointers both point to the same memory, and the contents of the memory are the same, so calling free in main() will realease the memory.
Here is a correct approach
char *Pointer;
//,,, maybe allocating memory and assigning its address to Pointer
//... though it is not necessary because it is a global variable and
//... will be initialized by zero. So you may apply function free to the pointer.
char *MyChar = DoSomething( Pointer );
char * DoSomething( char *Destination )
{
free( Destination );
//re-allocate memory
Destination = malloc( some number );
//then do something...
//finally
return Destination;
}
As for your code then
Type of the argument does not correspond to type of the parameter in function call
char *MyChar = DoSomething (&Pointer);
the type of the parameter is char * ( char *Destination ) while the type of argument is
char ** ( &Pointer )
As Destination is a pointer then instead of
free (*Destination);
you have to write
free( Destination );
It's because you are passing in an address of the pointer char *Pointer with the line
char *MyChar = DoSomething (&Pointer);
Since you are passing in the address of the pointer in your function DoSomething it sees the functional scope variable Destination as a pointer to an address that is the address of the pointer Pointer.
So rather than passing in the address of Pointer with
char *MyChar = DoSomething(&Pointer);
you need to pass in the pointer itself like so:
char *MyChar = DoSomething(Pointer);
which will allow you to use
free(Destination);
Notice the lack of & indicating the address of Pointer.

C free(): invalid pointer allocated in other function

I'm new in StackOverflow. I'm learning C pointer now.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int alloc(int* p){
p = (int*) malloc (sizeof(int));
if(!p){
puts("fail\n");
return 0;
}
*p = 4;
printf("%d\n",*p);
return 1;
}
int main(){
int* pointer;
if(!alloc(pointer)){
return -1;
}else{
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
I compile with: gcc -o main main.c
error: free(): invalid pointer: 0xb77ac000 ***
what's wrong with my code?
Arguments in C are always passed by value. So, when you call alloc(pointer), you just pass in whatever garbage value pointer contains. Inside the function, the assignment p = (int*)... only modifies the local variable/argument p. Instead, you need to pass the address of pointer into alloc, like so:
int alloc(int **p) {
*p = malloc(sizeof(int)); // side note - notice the lack of a cast
...
**p = 4; // <---- notice the double indirection here
printf("%d\n", **p); // <---- same here
return 1;
}
In main, you would call alloc like this:
if (!(alloc(&pointer))) {
....
Then, your code will work.
Everything in C is pass-by-value. This means that functions always operate on their own local copy of what you pass in to the function. Usually pointers are a good way to mimic a pass-by-reference scheme because a pointer and a copy of that pointer both contain the same memory address. In other words, a pointer and its copy both point to the same space.
In your code the issue is that the function alloc gets its own local copy of the pointer you're passing in. So when you do p = (int*) malloc (sizeof(int)); you're changing the value of p to be a new memory address, but the value of pointer in main remains unchanged.
You can get around this by passing a pointer-to-a-pointer, or by returning the new value of p.
You have two major problems in your code.
First, the alloc function creates a pointer via malloc, but never frees it, nor does it return the pointer to the calling function. This guarantees the memory the pointer addresses can never be freed up via the free command, and you now have memory leaks.
Second, the variable, int* pointer in main, is not being modified as you would think. In C, function arguments are "passed by value". You have two ways to address this problem:
Pass a pointer to the variable you want to modify (in your case, a pointer to a pointer to an int)
Have the function return the pointer to the function that called it.
Here are two implementations of my recommendations:
Approach 1
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p);
int alloc(int** p) {
if (!p) {
printf("Invalid argument\n");
return (-1);
}
if ((*p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (-1);
}
**p = 123;
printf("p:%p - *p:%p - **p:%d\n", p, *p, **p);
return 0;
}
int main(){
int* pointer;
if(alloc(&pointer) != 0){
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
return 0;
}
Sample Run for Approach 1
p:0xbfbea07c - *p:0x8656008 - **p:123
&pointer:0xbfbea07cointer - pointer:0x8656008ointer - *pointer:123
Approach 2
#include <stdio.h>
#include <stdlib.h>
int* alloc(void) {
int* p;
if ((p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (NULL);
}
*p = 123;
printf("p:%p - *p:%d\n", p, *p);
return p;
}
int main(){
int* pointer = alloc();
if(pointer == NULL) {
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
pointer = NULL;
return 0;
}
Sample Run for Approach 2
p:0x858e008 - *p:123
&pointer:0xbf9bb1ac- pointer:0x858e008- *pointer:123
You are passing the pointer by value into your alloc function. Although that function takes a pointer to an int, that pointer itself cannot be modified by the function. If you make alloc accept **p, set *p = ..., and pass in &pointer from main, it should work.
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p){
*p = (int*) malloc (sizeof(int));
if(!*p){
puts("fail\n");
return 0;
}
**p = 4;
printf("%d\n",**p);
return 1;
}
int main() {
int* pointer;
if(!alloc(&pointer)){
return -1;
} else {
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
If you want a function to write to a non-array parameter of type T, you must pass a pointer to that parameter.
void func( T *ptr )
{
*ptr = new_value;
}
void foo ( void )
{
T var;
func( &var ); // writes new value to var
}
If T is a pointer type Q *, it would look like
void func( Q **ptr )
{
*ptr = new_pointer_value;
}
void foo ( void )
{
Q *var;
func( &var ); // writes new pointer value to var
}
If Q is a pointer type R *, you would get
void func( R ***ptr )
{
*ptr = new_pointer_to_pointer_value;
}
void foo ( void )
{
R **var;
func( &var ); // writes new pointer to pointer value to var
}
The pattern is the same in all three cases; you're passing the address of the variable var, so the formal parameter ptr has to have one more level of indirection than the actual parameter var.
One sylistic nit: instead of writing
p = (int *) malloc( sizeof (int) );
use
p = malloc( sizeof *p );
instead.
In C (as of the 1989 standard), you don't need to cast the result of malloc; void pointers can be assigned to other pointer types and vice versa without needing a cast (this is not true in C++, but if you're writing C++, you should be using the new operator instead of malloc anyway). Also, under the 1989 version of the language, using the cast would mask a bug if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope. That hasn't been a problem since the 1999 version, though, so now it's more a matter of readability than anything else.
The type of the expression *p is int, so the result of sizeof *p is the same as the result of sizeof (int). This way, if you ever change the type of p, you don't have to modify the malloc call.
To allocate an array of values, you'd use something like
T *p = malloc( sizeof *p * NUM_ELEMENTS );
or, if you want everything to be zeroed out initially, use
T *p = calloc( sizeof *p, NUM_ELEMENTS );

Resources