It seems there are many questions of the form "should I declare X?" but not this specific one. I hope it is ok to ask this.
The title says it all: why should I declare a pointer? Even better: there are risks if I do not declare the pointer? Consider the following examples:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <string.h>
void func(int *ptr);
int main (int argc, char **argv)
{
int a;
int *PTRa;
a = -1;
PTRa = &a;
func(PTRa);
printf("%d\n", a);
return 0;
}
void func(int *ptr)
{
*ptr = 1;
return;
}
I get a=1. In this case I would say the pointer is declared (and assigned as well): I have the line int *PTRa; (declaration) and the line PTRa = &a; (assignment). The results is correct. I don't get any warning.
Imagine now to replace the main with the following:
int main (int argc, char **argv)
{
int a;
a = -1;
func(&a);
printf("%d\n", a);
return 0;
}
Here I do not declare the pointer but just give the address of a to func. The result is correct and I don't get warnings.
My understanding is that the two approaches are identical: func always gets the same input, the address of a. I would even dare to say that I feel the second approach to be better, as I feel it to be clearer and I feel the variable PTRa to be useless and somewhat redundant. However, I always see codes where the first approach is used and I have the feeling I will be told to do so. Why?
You are correct: there's no point in declaring a pointer in your example. A pointer is just a variable that holds an address. The cleaner approach is to pass directly the address of the variable: func(&a) instead of doing one extra step and declaring PTRa.
Note that not all cases are this simple. For example, if you want to have an array of ints, but you want to be able to grow that array dynamically because you don't know how big it should be you have to declare a pointer:
int count = ...; // get the count from the user, from a file, etc
int *list_of_ints = malloc(sizeof(int) * count);
if (list_of_ints == NULL)
{
// malloc failed.
printf("Not enough memory!\n");
exit(1);
}
// Now `list_of_ints` has enough space to store exactly `count` `int`s
EDIT: as #paulsm4 pointed out in a comment, the question Why use pointers? is a great source of information related to this topic.
EDIT 2: one good reason to want a pointer to the address of a variable might be that you want a pointer inside a structure or array:
struct foo
{
int x;
};
struct bar
{
int y;
struct foo f;
};
struct bar b;
struct foo *ptr_foo = &b.f;
You can now work more easily with b.f because you're just working with a struct foo.
In this case there's no benefit in creating a separate pointer variable.
It might be necessary in more complex cases, just like it's sometimes necessary to create variables of any other type.
From the title, I thought you're talking about pointer type, but actually, you are asking if declaring a variable is needed.
Variable is a piece of memory, storing some numbers(bytes), and the type of the variable, indicating how you and your program interpret those bytes: integer? float? character? etc.
Pointer is the memory address, it could be of a variable, or a function, or something else.
A variable of pointer is a small area in the memory, storing the address of other(or even same) memory.
You decide if you need an extra variable to store the pointer. It's the same to the decision that if you want a variable to store an integer:
int v = -1;
abs(v); // use variable
abs(-1); // use constant
Related
I'm basically curious if you could do something like this, without the use of pointers:
int myVariable = 0;
int varPointer = &myVariable;
*varPointer += 1; //This obviously won't work, but explains the concept
Yes, I know you can do this with pointers. I want to know if it can be done without pointers.
EDIT>
I want to be able to refer to an address contained in a variable without pointers.
The question is basically, "Can you achieve pointer functionality without using actual pointers? If so, how?"
This code uses integer arithmetic instead of pointer arithmetic:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
int myVariable = 0;
uintptr_t varPointer = (uintptr_t)&myVariable;
varPointer += sizeof myVariable;
return 0;
}
You say in comments:
pointers /can/ contain addresses, but do not necessarily.
Pointer variables must either be null pointers or contain the address of an object. If your code appears to do otherwise then your program has already caused undefined behaviour.
"Hex" has nothing to do with it; base 16 is a way of outputting numbers and you can use any base you like.
Bear in mind that pointers do not necessarily correspond to numbers. On platforms where they don't, then uintptr_t will not exist.
#include <stdio.h>
#include <stdint.h>
int main(void){
int myVariable = 0;
intptr_t varPointer = (intptr_t)&myVariable;
*(int*)varPointer += 1;
printf("%d\n", myVariable);
return 0;
}
Below I have to examples of code that do the same thing and give the same output. In the first, I use pointer to pointer argument passing to eliminate the use of ans as a global. In the second, I madeans a global which eliminated the additional uses of * when dealing with pointer to pointer:
Example 1:
// pointer to pointer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
unsigned char serial[] = {
0x1,0x2,0x3,0x4
};
void checkSerial(unsigned char* buf, unsigned char ** ans)
{
int i;
unsigned char *part;
part = 0;
i=2;
part = &buf[i];
*ans = (unsigned char*)malloc(2);
memset(*ans,0,2);
memcpy(*ans,part,2);
printf("0x%x\n",**ans);
++(*ans);
printf("0x%x\n",**ans);
}
int main(void)
{
unsigned char *ans, *buf;
while(1)
{
buf = malloc(4);
memset(buf,0,4);
memcpy(buf, serial, sizeof(serial));
checkSerial(buf, &ans);
--ans;
printf("the value is 0x%x\n", *ans);
free(buf);
free(ans);
sleep(3);
}
return 0;
}
Example 2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
unsigned char serial[] = {
0x1,0x2,0x3,0x4
};
unsigned char ans[2];
void checkSerial(unsigned char* buf)
{
int i;
unsigned char *part;
part = 0;
i=2;
part = &buf[i];
int j;
for(j=0;j<2;j++)
{
ans[j] = part[j];
}
printf("0x%x\n",*ans);
++(*ans);
printf("0x%x\n",*ans);
}
int main(void)
{
unsigned char *buf;
while(1)
{
buf = malloc(4);
memset(buf,0,4);
memcpy(buf, serial, sizeof(serial));
checkSerial(buf);
printf("the value is 0x%x\n", *ans);
free(buf);
sleep(3);
}
return 0;
}
Which technique is preferred in C?
Avoid global variables when it is not necessary. Going with first example is preferable.
Global variables are easily accessible by every functions, they can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
Keep variables as close to the scope they are being used in as possible. This prevents unexpected values for your variables and potential naming issues.
I personally don't like defining global variable where there is ways to avoid it.
But some guys say that, the concept of pointer is very much confusing. I don't feel that though..
My advice, if you get confuse with pointers try to avoid it with defining global variable. Otherwise, use pointers... :)
TL;DR: Solutions 1 and 2 are both bad.
The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time, if those are really known at compile-time then , just don't use malloc at all, declare variables on the stack. In C, generally avoid dynamic memory allocation as much as possible and prefer to create buffers which can hold the maximum size a buffer can have in your application. That avoids this kind of problems in the first place. The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time. The only place where dynamic memory allocation can be useful is for buffers whose sizes are unknown at compile-time, but you can still avoid it (see below). If buf is an incoming message, and ans the answer to this message, the size of ans can be unknown at compile-time, at least if you use variable-length messages.
Your version 2 is not working and can not work! First you declared ans to be an array of size 1 and iterate over it until index 2(now you edited that). Second to declare the array ans as global you would need to know its size at compile-time, and then of course if you knew its size at compile-time you would just declare the array ans in the function checkSerial. Moreover, when you declare a variable which is used by several functions in C don't forget to declare it static, otherwise it can be accessed from all files in your project.
A solution avoiding dynamic allocation, notice you avoid the disadvantages of your 2 solutions: the pointer to pointer and the global variable, and moreover your program can not leak since you don't use dynamic allocation:
enum {MSG_MAX_SIZE = 256 };
typedef struct message {
uint8_t payload[MSG_MAX_SIZE];
size_t msg_size;
} message_t;
void checkSerial(const message_t *buf, message_t *ans)
{
//parse buf and determine size of answer
...
...
//fill answer payload
ans->msg_size = buf[42];
}
int main(void)
{
while (1) {
message_t buf;
getMsg(&buf);
message_t ans;
checkSerial(&buf, &ans);
}
}
I am really at a loss about this program.I want it to return the address of an integer array of 5 elements.But it just wont' work.How to make a C function return the address of an array instead of the address of its first element(base address)?I know both are same numerically but their types are different,that's why I ask.
Also to put it precisely, how to declare the prototype of such functions?I understand how to declare the argument part of the prototype (using abstract declarators) but just don't know how to declare the return type if we are to return addresses of arrays or functions.I only know that if we place a '*' before function name in declaration that it means the function returns a pointer to the respective primary data type like int,char or float.
#include<stdio.h>
int (*)[5]fun(int (*)[5]);
int main(void)
{
int arr[5];
printf("%u",fun(&arr));
}
int (*)[5]fun(int (*arr_add)[5])
{
return arr_add;
}
HELLO!! DANIEL FISCHER Thanks for your answer.You answered it exactly and in a concise way.But I am choosing H2CO3 's answer as that brilliant Hungarian kid took the trouble to explain it to me in detail through chat.It's really hard to pick the best answer when so many bright people are answering.Thanks everyone!!
Perhaps explaining how it works is of some use.
The idea behind C's declaration syntax is that "declaration mimics use". So you want
a function
fun( )
taking a pointer to an array of five int
fun(int (*arr)[5]) // or without argument name fun(int(*)[5])
and returning a pointer
(*fun(int (*arr)[5]))
to an array of five
(*fun(int (*arr)[5]))[5]
int
int (*fun(int (*arr)[5]))[5];
Or, you can also go from the result, that should be a pointer to an array of five int,
int (*result)[5];
and substitute result with the call (result = fun(arr))
int (*fur(arr))[5];
and then add the type of the argument/replace the argument with its type:
int (*fun(int(*)[5]))[5];
Here you are:
int (*fun(int (*arr)[5]))[5]
{
return arr;
}
If you want to return the address of the first element (as opposed to the address of the array itself), that's a different type:
int *fun(int (*arr)[5])
{
return &(*arr)[0];
}
This is wrong:
printf("%u",fun(&arr));
It should really be:
printf("%p", (void*)fun(&arr));
As for the address of the array, it is going to be the same as the address of its first element.
Now, the declaration and definition should really look like:
int (*fun(int(*)[5]))[5];
Fixed code:
#include<stdio.h>
int (*fun(int (*)[5]))[5];
int main(void)
{
int arr[5];
printf("%p\n", (void*)fun(&arr));
}
int (*fun(int (*arr_add)[5]))[5]
{
return arr_add;
}
ideone
Let's say that any C function has a pointer already declared, but not assigned any value yet. We will int for our examples.
int *ptr;
The goal of the function is not to assign ptr any dynamic memory on the heap, so no malloc call. Instead, we want to have it point to an array of fixed size n. I know I could accomplish this like so:
int arr[n];
ptr = arr;
However, the code could get very messy and hard to read if we need to do this many times in a function, ie, a struct of many pointer fields all need to point to an array of fixed length. Is there a better way to accomplish this in one line? I was thinking of something similar to below, but it looks too ambiguous and uncompilable:
int *ptr;
// Many other things happen in between...
ptr[n];
***EDIT***
Here, the below additional information may help guide some more answers (not saying that the current answers are not fine). In my use case, the pointers are declared in a struct and, in a function, I am assigning the pointers to an array. I want to know if there is a simpler way to accomplish this than in the below code (all pointers to point to fixed-length array):
struct foo {
int* a;
short* b;
char* c;
...
};
void func(void) {
struct foo f;
int n = ...;
int tempArr1[n];
f.a = tempArr1;
short tempArr2[n];
f.b = tempArr2;
char tempArr3[n];
f.c = tempArr3;
...
}
You cannot declare an array and assign it to an existing pointer in a single declaration. However, you can assign an array pointer to a newly declared pointer, like this:
int arr[n], *ptr = arr;
If you insist on staying within a single line, you could use an ugly macro, like this:
#define DECL_ASSIGN_INT_ARRAY(name,size,pointer) int name[(size)]; pointer = name;
The clarity of this one-liner is far lower than that of a two-line version from your post, so I would keep your initial version.
EDIT (in response to the edit of the question)
Another option is to create an unused pointer variable in a declaration, and assign your pointer in an initializer, like this:
void func(void) {
struct foo f;
int n = ...;
int tempArr1[n], *tempPtr1 = f.a = tempArr1;
short tempArr2[n], *tempPtr2 = f.b = tempArr2;
char tempArr3[n], *tempPtr3 = f.c = tempArr3;
...
}
This seems like a clear case where you're in need of some refactoring. Take the similar statements, extract them into a new function (by passing a reference to the struct and the data you want the struct fields to point to) and give this new function a meaningful name.
This is probably more maintainable and readable than some fancy pointer arithmetic shortcut that you'll forget about in a few weeks or months.
The difference between ptr and arr in you example is you can change ptr's value. So I guess you want to move ptr through the array.
So how about this:
int arr[n], id=0;
And you change the value of id and use arr+id as ptr.
I guess the way to do this is to use a macro. Something like (untested)
#define autoptr(name,size) int Arrayname[size]; name = Arrayname;
I'm not clear why this is helping I think it might "look ugly" but will be easier to maintain without the macro. In general, hiding what you are actually doing is a bad thing.
Title pretty much sums this up. How come it's possible that i can assign a locally created Point a (in the function ReadPoint()) into a variable that's in a different scope. Doesn't the locally created Point a gets 'popped' away along with stack of function readPoint() ? What exactly is going on ?
struct Point readPoint(void)
{
struct Point a;
printf("x = ");
scanf("%lf",&b.x);
printf("y = ");
scanf("%lf",&b.y);
return a;
}
int main(int argc, char **argv) {
Point test = readPoint();
printPoint(test);
return 0
}
structs are no different to primitive types in this regard. It's exactly the same principle as:
int foo(void)
{
int x = 5;
return x;
}
int main(void)
{
int y = foo();
printf("%d\n", y);
}
The details of how this is achieved are implementation-dependent. But usually, the return value (whether it's an int or a struct) is placed onto the stack by the called function, and then the caller then can then access that stack location.
The struct is "copied", byte by byte, into test in main...just like returning an int from a function and assigning it to a variable.
This, however, wouldn't happen if you were returning a pointer to the struct and the dereferencing it and assigning (or something similar).
When returning, you'll create a copy of the object (with all members of the struct), but the local variable/object is still destroyed.
This will work unless you try to return a reference or pointer (in these cases your compiler should warn you about this stupid idea). This will work fine, unless you're trying to create a copy of something working with pointers.
In C++ this would include references too.
This is because on return from readPoint() all structure values are copied to another locally defined structure test. Structure a does not survive.
What you're seeing is structure assignment. Almost all modern compilers can handle this.