Why do we need int *ptr = NULL;? - c

I don't quite understand why in this example we need a part int *ptr = NULL;. I understand what pointers are, but why do we need this * (points at a value attached to an address) here? And why do we need NULL here?
#include <stdio.h>
int main() {
int a[5] = {22, 33, 44, 55, 66};
int *ptr = NULL;
int i;
ptr = a;
for (i = 0; i < 5; i++) {
printf("%d ", *(ptr + i));
}
}

This intermediate initialization
int *ptr = NULL;
is redundant. You could write at once
int *ptr = a;
Moreover such an initialization is a bad programming style. Each variable should be declared and initialized where it is used. Otherwise the code will confuses users as it confused you.
I would rewrite the program the following way
#include <stdio.h>
int main( void )
{
int a[] = { 22, 33, 44, 55, 66 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( const int *ptr = a; ptr != a + N; ++ptr )
{
printf( "%d ", *ptr );
}
putchar( '\n' );
}
There are cases when the same one pointer can be used in various contexts. In this case it makes sense to declare it and initialize with NULL. But your simple program is not the case.

In your case int *ptr = NULL is completely redundant as you could just write int *ptr = a as Vlad has already said, but more generally it is a good idea to initialise pointers to NULL because if for some reason you have an error in your code and you need to debug it, it is a lot easier to debug what is happening to the pointer if it starts as NULL than if you hadn't initialised it and it is filled with some garbage value.

I don't quite understand why in this example we need a part int *ptr = NULL;.
[...]
why do we need this * (points at a value attached to an address) here?
You are mistaking the significance of the *. In that context, it is not the unary * operator. Rather, it is part of the syntax for declaring a variable whose type is a pointer type. The declaration declares ptr as a variable of type int *, i.e. pointer-to-integer. Without the *, the declaration would be designating ptr's type as int, not as a pointer type.
And why do we need NULL here?
You don't. The = NULL is an initializer for variable ptr, defining its initial value, but you assign a different value to that variable before ever reading it, so the initializer has no practical significance.
Some people are inclined to provide such initializers as a matter of course, on the theory that it avoids accidental usage of wild pointers and / or allows (otherwise-)uninitialized pointers to be detected, but as Emerson wrote, "A foolish consistency is the hobgoblin of little minds." The initializer serves no useful purpose in this particular code. If one insists on providing an initializer then there's no reason not to initialize ptr directly to a:
int *ptr = a;
as your other answers also suggest.

Related

Proper way to read 'int * ptr=&x'

The following code is easily interpreted as
int x=4;
int *ptr; // ptr is a pointer to an int
ptr=&x; // the address of x is assigned to the pointer ptr
But the following equivalent code, may read misleadingly like
int *ptr=&x; // the address of x is assigned to *ptr, which is an integer
that is it seems to be interpreted as assigning the address of x to the pointed value *ptr (int *ptr )= &x
The correct interpretation as the one when declaration and initialization are separated should be written something like int *(ptr = &x),to make evident that the assignment is to the pointer and not to the pointed location but this gives an error, why is that? And what is the best way to read and think of int *ptr=&x?
This is, admittedly a weird part of C and it's mostly due to C's evolution.
In C's syntax, declarations aim to mirror use, so that after int *x;, *x resolves to an int and *x=42 assigns to that int. But initializations, which are started with = after the specifiers declarator part of a declaration, are syntactically and semantically different from an assignments.
(Initialization can "assign" to static/filescope variables and such an assignment generates no code: it simply contributes to the makeup of the resulting binary. Assignments always generate code unless optimizations can delete it)
Initializations and assignments used to be very differently looking in prehistoric C, where you'd initialize without the = sign as in int x 42;. (Even after the = was added to the syntax of initializations, it was long impossible to initialize local, nonstatic, variables which meant situations such as int *p = &x; didn't arise all that often.)
The old syntax had problems (would int x (42); also declare and initialize x or would it be a function declaration?) and that's why it was replaced, but I like how it emphasized that initializations are different from assignments.
Unfortunately with the new syntax (as in int x, *p = &x;) this distinction is not all that apparent, and you simply have to remember that when you have type specifiers (int) at the left end, then the = does not denote an assignment where you can just look at *p = &x but rather that it's an initialization where you have to look at the whole declaration and see what's declared (x as an int and p as a pointer to int) . The = in that context then initializes the declared identifier.
int * is the type, so it makes perfect sense. It's just that pointer notation in C can take some effort to get used to. But look at this code
typedef int* int_ptr;
int x;
int_ptr ptr = &x;
Same thing. However, it's often advised to NOT typedef pointers.
The confusion comes from that * serves two roles. It is BOTH to name a type AND to dereference a pointer. An example of the first is sizeof(int*)
If you declare several pointers at once it looks messier, but it's still the same. In general, it's recommended to not declare more than one pointer at once. Because if we would like to do the above thing with two pointers, it would look like this:
int *pa = &x, *pb = &x;
That's the same as
int *pa = &x;
int *pb = &x;
And this does something completely different and will generate a warning because you're assigning the address of a variable to the pb variable that has type int
int *pa = &x, pb = &x;
However, using the typedef from above, you can (but probably shouldn't) do this:
int_ptr pa=&x, pb = &x;
But one way to think of it is that it makes no sense at all in any situation to dereference an uninitialized pointer.
And what is the best way to read and think of int *ptr=&x?
Take the fact that it does not make sense to dereference an uninitialized pointer. And you're doing an initialization of a pointer, and therefore you should initialize it with a (valid) address.
Ok, I see that, another thing. If the type is int* why is it almost always written like with the * next to the pointer variable instead, like int *ptr?, it would make more sense, even if it is the same to write it like int* ptr.
Because, then it would be MUCH easier to forget the asterisk if you declare several pointers at once. That would give the impression that int* p,q; declares two pointers.
C pointer syntax is clunky. It's a very old language. Just get used to it. It will never change. Just for fun, here is a page that can tell what a declaration is https://cdecl.org/ so try these:
int (*p)[3]
int *p[3]
const int *p[3]
int *const p[3]
const int (*p)[3]
int (*const p)[3]
You could write
int ( *ptr ) = &x;
or even like
int ( * ( ptr ) ) = &x;
Though this record
int *ptr = &x;
is clear for each C programmer because it is a declaration and not an assignment statement. Moreover in C opposite to C++ declarations are not statements.
That is 1) you may not enclose a declaration in parentheses as you wrote (int *ptr )= &x and 2) you may enclose a declarator in parentheses.
If to follow your logic then you should write the declaration like
int *p = ( p = &x );
that makes the declaration more confusing.:)
Here is a demonstrative program that shows some examples of declarations and initializations of a pointer.
#include <stdio.h>
int main(void)
{
int x = 10;
int *p1 = &x;
int ( *p2 ) = &x;
int ( *( p3 ) ) = &x;
int typedef *T;
T ( p4 ) = &x;
printf( "*p1 = %d\n", *p1 );
printf( "*p2 = %d\n", *p2 );
printf( "*p3 = %d\n", *p3 );
printf( "*p4 = %d\n", *p4 );
return 0;
}
The program output is
*p1 = 10
*p2 = 10
*p3 = 10
*p4 = 10
Pay attention to that in C as in many other languages some symbols are overloaded and their meanings depend on the context. For example the symbol & can denote the address of operator and the bitwise AND operator and by the way in C++ this symbol also can denote a reference.
Compare the following.
int n = 5; // (a) defines 'int' variable 'n' and initializes it to '5'
int *p; // (b) defines 'int*' pointer variable 'p`
p = &n; // initializes 'p' to '&n'
int *p1 = p; // (c) defines 'int*' pointer variable 'p1' and initializes it to 'p'
// syntactically, it looks just like (a), but for a pointer type
int *p2 = &n; // (d) same as (b) and (c) combined into a one-liner
int n3 = 7, *p3 = &n3; // (e) same as (a), (b) and (c) combined into a one-liner
when declare a pointer, int p is equal to int p; int* is a type.

How to pass the 2D array point to the other functions?

I have a question. I wanna pass my own 2D array to pass function.And in that function,i will change my own array.So,there is a return.What i exactly know is that the code blow can be accepted by the compiler.But, i don't why it is.When i take the int (* aaa)[3]; out of the main function,it works well.But , when it is inside the main,there will throw an exception that unable to use the uninitialized aaa.I wonder why could this happan.
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int (* aaa)[3];
int main() {
aaa = pass(aaa);
printf("%d", aaa[0][2]);
}
this could work.
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int main() {
int (* aaa)[3];
aaa = pass(aaa);
printf("%d", aaa[0][2]);
}
but,this can't work.
When int (* aaa)[3]; appears outside of any function, it aaa is automatically initialized to a null pointer. When it appears inside a function, it is not initialized.
The code aaa = pass(aaa); passes aaa to the routine named pass. This is a use of the value of aaa. When aaa has been initialized, that is fine. But, when aaa is not initialized and you attempt to pass its value, the behavior is not defined by the C standard. This is what the compiler is warning you about.
Next, let’s examine this code:
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
This code never uses the value of a that is passed to it. When a function is called, its parameter, a in this case, is given a value (which comes from the argument the caller passed). This parameter is a separate variable from the argument. Assigning a a value with a=(int*)malloc(sizeof(int*)*2); does not change the value of aaa in the calling routine. So this code assigns a new value to a without using the old value.
Because of that, the routine does not need a parameter passed to it. It could be written to use a local variable instead, like this:
int (*pass(void))[3] {
int (*a)[3] = malloc(2 * sizeof *a);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
The void in this means pass does not take any arguments.
Note that I changed malloc(sizeof(int*)*2 to malloc(2 * sizeof *a). sizeof(int*)*2 is wrong because it requests space for two pointers to int. But a points to arrays of three int, so, to get two of those, you need space for two arrays of three int. That is 2 * sizeof(int [3]). However, it is easier to write this as malloc(2 * sizeof *a), which means “two of whatever a points to”. This is also better because it reduces the frequency with which errors are made: Even if the declaration of a is changed, this sizeof *a will automatically adjust without needing to be edited. With sizeof(int [3]), any edit to the declaration of a would require another edit to the sizeof.
Also, I removed the (int*) to cast the result of malloc. In C, a void *, which is the type malloc returns, will automatically be converted to whatever object pointer type it is assigned to. There is no need for an explicit cast, and using an explicit cast can mask certain errors. (However, if you compile the program with a C++ compiler, it will complain about the lack of a cast, because the rules are different in C++.)
Since the function is returning a pointer to an array of three int, not an pointer to an int, I changed its declaration to int (*pass(void))[3].
With these changes, the program could be:
#include <stdio.h>
#include <stdlib.h>
int (*pass(void))[3]
{
int (*a)[3] = malloc(2 * sizeof *a);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int main(void)
{
int (*aaa)[3] = pass();
printf("%d\n", aaa[0][2]);
}
maybe this helps you a bit to see that C is 'flexible' when it comes to arrays.Because in the first part the assumed array declaration is given by datalen in malloc of the initAAA function and returns the pointer to the memory that is allocated. And still in the for loop we can access the data with index.
The second part of main declares just same data 'bbb' as the first 'aaa' but this time not as pointer and the initiation of the data fields with zeros (0) is done with the curly parenthesis. {}. A boring for loop thru all the indexes and set each data field with int 0 would just do it also. But who wants more code than needed.
#include <stdio.h>
#include <string.h>
int *initAAA(int *p, uint entrys) {
size_t datalen = entrys * sizeof *p;
p = malloc(datalen); // p is a pointer here.
// copy character '0' starting at address of p up to datalen addresses
// easier then writing a for loop to initiate safely.
memset(p, 0, datalen); // defined in string.h
return p;
}
int main(void) {
const uint maxAssets = 3;
const uint entrysPerAsset = 2;
int *aaa = NULL; // always a good idea, to set pointers to NULL before allocating memory for it. Because you can check if (aaa==NULL) initAAA(...
uint entrys = maxAssets * entrysPerAsset;
aaa = initAAA(aaa,entrys);
printf("address:%p items:%d \n",aaa, entrys);
for (uint i = 0; i < entrys; i++) {
printf("%d ", aaa[i]);
}
free(aaa); // malloc without free, bad idea!
printf("\n---\n");
int bbb[maxAssets][entrysPerAsset] = {0,0,0,0,0,0};
for (uint a = 0; a < maxAssets; a++) {
for (uint e = 0; e < entrysPerAsset; e++) {
printf("%d ", bbb[a][e]);
}
}
// bbb does not need free(bbb); because it is released with the function end.
// and yep, there was no malloc for bbb. so we are done.
}
and by the way. welcome to C.

Structures and linked list accessing.

#include <stdio.h>
int main(void)
{
typedef struct{
int a;
} cool;
cool x;
(&x)->a = 3;
x.a = 4;
}
I was wondering if the (&x)-> a does the same thing as the x.a. I coded both of them up, and it seemed that both of them changed the value of x.a. I know it must be a pointer on the left side of ->, but the (&x) seems to work without problem. Printing out x.a works for both of them, and gives me the correct answer. I looked up a lot about pointers, linked list, and structures and am still not able to find out the answer. Would it be possible to get an explanation? Thank you!
The -> operator expects a pointer on the left hand side. &x returns the address of x so it satisfies that requirement (even if it is totally redundant). To think about it another way...
cool *y = x;
y->a = 3;
The . operator expects a stack allocated struct on the left hand side. x is that, so x.a works fine.
You can also go the other way, if you have a pointer y you can dereference it with *y and use . on it: (*y).a. This is also totally redundant.
The & prefix operator returns the memory address of whatever object you put it in front of.
This means that you have to put it in front of objects that actually have a memory address. For example, literals and temporary expression results don't necessarily have an address. Variables declared with register storage class don't have an address, either.
Thus:
int i = 5;
&i; // works
&5; // Nope!
&(i + 1); // Nope!
&i + 1; // Works, because &i has higher precedence than +1.
So what does the address of an object give you? It is a pointer to the object. This is how you can do dynamic memory allocation using the heap. This is where functions like malloc() come in. And this is how you can build arbitrarily large data structures.
In C, arrays are represented as pointers. So arrays and pointers are often used interchangeably. For example:
char buffer[100]; // array
strcpy(buffer, "hello"); // strcpy is declared to take (char *, const char *)
The opposite of the address_of operator is the * dereference operator. If I declare a pointer to something, I can get "what it points at" using this syntax:
int i = 5;
int *pi = &i; // pointer to int. Note the * in the declaration?
i + i; // 10
i + *pi; // Also 10, because pi "points to" i
In the case where you have an aggregate type like a struct or union, you would have to do something like this:
struct {
int a;
} s;
s.a = 5;
/* ??? */ ps = &s; // pointer to s
s.a; // 5
(*ps).a; // Also 5, because ps points to s.
ps->a; // 5, because a->b is shorthand for (*a).b
This only works, of course, if you have a pointer to an object that CAN use the .member and that has an appropriately named member. For example, you can't do this:
i = 5;
pi = &i;
pi->a; // WTF? There is no i.a so this cannot work.
If you have a pointer, you can take the address of it. You then have a pointer to a pointer. Sometimes this is an array of pointers, as with the argv array passed to main:
int main(int argc, const char *argv[]);
int main(int argc, const char **argv); // Effectively the same.
You can do weird stuff with pointers to pointers:
int i = 5;
int j = 100;
int * pij;
for (pij = &i; i < j; ) {
if (i & 1) {
*pij *= 2;
pij = &j;
}
else {
i += 1;
*pij -= 1;
pij = &i;
}
}
Note: I have no idea what that code does. But it's the kind of thing you can wind up doing if you're working with pointers.

C returning array in function

Im relatively knew to C, i am used to program in Java so i find C a little bit difficult in what concerns arrays. I still cofuse myself with this cases:
int a [];
int* a;
int *a;
In java, i would do something like this to return an array in a function:
int [] returnArr(int [] a){
... modify a ...
return a;
}
int [] a = {...};
int [] b = returnArr(a); ##
How can i do the same in C, specially the parts with ##.
EDITED:
I have this function:
float *normalizeValues(float *v, float maxY){
int size = sizeof(v) / sizeof(float);
float max = findMax(v);
float ratio = maxY / max;
int i;
for(i = 0; i < size ; ++i){
v[i] = v[i] * ratio;
}
return v;
}
And im doing the following:
float vert [] = {306, 319, 360, 357, 375, 374, 387, 391, 391, 70, 82, 94, 91, 108, 114, 125, 127, 131};
int i = 0;
float *vert2;
vert2 = normalizeValues(vert, 0.7);
for(i = 0; i < sizeof(vert2) / sizeof(float); ++i){
fprintf(stdout,": %f\n",vert2[i]);
}
And the output is only 1 element.
EDIT: To directly answer your updated question: you have to pass in the size of the array. C has no mechanism to store the size of arrays like Java does. If the compiler knows about the size of the array because the array is a global or local variable, not dynamically allocated, then you can use the sizeof() operator. Otherwise, you have to know the size separately, or use sentinel values in your array (such as a 0.0 at the end, or a NULL).
As for arrays, pointers and arguments in general, see below:
You will be returning a pointer to the array, which is indicated with the '*' syntax:
int *returnArr(int[] a) {
// modify a...
return a;
}
int a[] = { ... };
int *b;
b = returnArr(a);
A few things to note:
You can't do assignments in variable declarations that involve non-constant expressions (e.g., function calls). This might have changed in C99, though.
The brackets go after the variable name, unlike in Java where they are part of the type. Even though Java's syntax is more consistent, it doesn't quite make sense in C where you often give the array size in the brackets in the variable declaration:
int a[3] = { ... };
There's no way to specify that a function returns an array as opposed to a plain pointer. In C, array references decay to pointers (though pointers and arrays are NOT the same thing, as is commonly claimed). That means that whenever you pass an array around, C only provides a means to a pass a pointer to the array. The whole array isn't actually copied. As it happens, the name of the array is also a pointer to the first element of the array.
Please also take note of what user268396 says in their answer. If you are planning to create a new array and return it, you'll need to either allocate the array dynamically, or have a pointer to an already allocated array be passed in (which is what it seems like you are kind of doing anyway).
You can't. When the function returns the stack frame will be wiped out (typically) and your generated array will be clobbered by that. You can however edit the function prototype to accept a pointer to the array to modify. That kind of function argument is known as an "output parameter". Example:
void function func(int a, int b, int[2] to_modify)
{
to_modify[0] = a;
to_modify[1] = b;
}
int main()
{
int foo[2];
func(1, 2, foo);
printf("Result: foo[0] = %d, foo[1] = %d\n", foo[0], foo[1]);
return 0;
}
This will print "Result: foo[0] = 1, foo[1] = 2".
Hope this helps
#include<stdio.h>
void change(int *c)/*Pointer c now has the first location of the array a[]*/
{
*(c+0) = 0;/*assign values to the array by adding step-size to the first array position*/
*(c+1) = 1;
*(c+2) = 2;
*(c+3) = 3;
*(c+4) = 4;
}
main()
{
int a[5]={10,20,30,40,50}; /* Declare and Assign an array a[] of size 5.*/
int *b = a; /*Declare and assign a Pointer to the location of the array.*/
change(b); /*pass the pointer(which is now pointing to first position of array) to the change() function.*/
printf("%d,%d,%d,%d,%d,",a[0],a[1],a[2],a[3],a[4]);/*Print the changed value.*/
}
Output: 0,1,2,3,4,
From Java point of view, Pointers are simply like(not exactly) Object references.
Object O;
O = New SomeClassName();
Like Object Reference O is pointing to some Actual Object of type SomeClassName, so does pointers in C:
int *b;
b = &a;
Variable b is simply pointing to the address location to a.
Taking a deep dive into array concepts:
int a[5];
int *b = a;
Here we are just saying like Mr.*b point to the first location of group a i.e. a[0].
Now the power pointer in C is that from now on, here after:
*b means a[0]
*(b+1) means a[1]
*(b+2) means a[2]
*(b+3) means a[3]
*(b+4) means a[4]
This means you change in *(b+4), you're changing a[4].
int* returnArr(int a[]){
//modify a
return a;
}
One need mention is when you use an array in the parameter list of a function, it will be converted into a pointer. So in main(...)'s declaration, char *argv[] and char **argv are actually same. In this case, int a[] and int* a are same. But array and pointer is not the same thing.
Take the following code as an example:
int a[10];
int main(){
int *p = a;
p[5] = 4;
return p[5];
}
p is a pointer, when we access p[i], note that the address of p is not the address of a, the content of p is the address of a. Then the code will:
access the memory to get the content of p, i.e. the address of a.
compute the offset based on i and type of the pointer(int).
access the memory to get the result.
a is an array of int, if we access a[i], the address of a is just the address of a[0], the code will:
Compute the offset based on i and the type int.
Access the memory.
Pointer and array are different types. So if you declare int *p in one file and use it in that file, but define the p as an array in another file, that will cause problem.
You may also wonder about int *p = a, in ANSI, if you use an array(its name) as an expression, the compiler will convert it into a pointer, pointing to the very first element of the array.
Update based on Jim Balter's comments:
If you use an array(its name) as an expression, the compiler will not always convert it into a pointer, pointing to the very first element of the array. For instance, in sizeof(p->q->a), p->q->a is an expression but if a is an array it isn't converted into a pointer.
"Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object.
In C, you can only return a pointer of an array in a function.
For example, if you want to return a string(array of char) in a function, you can return a pointer to a null-ended string. If you want to return an array of some other type(int, user-defined struct, etc), you can alloc some memory to store the array, and return the pointer of the array, return the size of the array in the parameter.
example:
int *function(int *size)
{
*size = 10;
int *intP = (int *)malloc((*size)*sizeof(int));
return intP;
}

If I have a void pointer, how do I put an int into it?

I have an array of arbitrary values, so I have defined it as an array of void pointers, so I can point to any kind of information (like int, character arrays, etc). However, how do I actually assign an int to it?
Take for example these initializations:
void* data[10];
int x = 100;
My intuition would think this, but this gives a compile error:
data[0] = malloc(sizeof(int));
*(data[0]) = x;
Also I thought about using &x, but I would take the address of a local variable, which (to my understanding) would be cleared after exiting from the procedure. So if I have a local variable x, how would I get it into a void pointer type of variable correctly?
*((int*)data[0])=x;
will do it.
You might want to consider using a union. Something like this:
union myvalues
{
int i;
double d;
long l;
};
You could then have
union myvalues *foo[10];
foo[0] = malloc(sizeof(union myvalues));
foo[0]->i = x;
You can also typedef the union. sizeof(union myvalues) will be the maximum of sizeof the members. So if you have int i; and char c[40] in the union, sizeof(union myvalues) will be 40. Writing to i will then overwrite the first 4 characters in c (assuming your ints are 4 bytes).
*((int *)data[0]) = x;
A copy of x will be made, so the fact it is a local variable is not important.
for aliasing reasons its far better to do
mempcy( data[0], &x, sizeof( int ) );
As it happens the compiler will optimise the memcpy call out as sizeof( int ) is a constant value but it won't break various aliasing rules.
Although you can use a cast to make the assignment, it is probably much cleaner to write the code like:
void *data[ 10 ];
int x = 100;
int *p;
p = malloc( sizeof *p );
data[ 0 ] = p;
*p = x;
try this:
data[0] = malloc(sizeof(int));
*((int*)data[0]) = x;
or
(int) (*(data[0])) = x;
don't forget to
free (data[0]);
afterwards.

Resources