I have some misunderstanding of the tutorial from my class. There is function called print_Arr(), it's generic function that gets pointer to arrays of double or integers and prints it.
Here is the code:
int main() {
int a[] = { 2,7,6,4,1 };
double b[] = { 12.5,2.7,3.0,5.5,5.9,1.0 };
print_Arr(a, sizeof(a)/sizeof(a[0]), sizeof(int), print_int);
print_Arr(b, sizeof(b)/sizeof(b[0]), sizeof(double), print_double);
}
void print_Arr(void* a, int size, int m, void (*print_func)(void* )) {
for (int i = 0; i <= size-1; i++)
{
print_func((char*)a + m*i);
}
}
void print_int(int* p) {
printf("%d\n", *p);
}
void print_double(double* num) {
printf("%f\n", *num);
}
Why do I have to make cast a to (char*) in this row:
print_func((char*)a + m*i);
I sent to print_Arr() generic function two type of arrays integers or doubles,
thus it is logically to cast a to int * or to double*.
But why is it casted to char*? What do I miss?
First, a word on why the cast is needed:
Pointer arithmetic makes use of the size of the type being pointed to. void is a forever incomplete type, that cannot be completed, so pointer arithmetic is not possible on a pointer to void type.
To add, for the additive operators, quoting from C11, chapter §6.5.6, constraints:
For addition, either both operands shall have arithmetic type, or one operand shall be a
pointer to a complete object type and the other shall have integer type.
and, from chapter §6.2.5,
The void type comprises an empty set of values; it is an incomplete object type that
cannot be completed.
That said, why the cast is to char* :
Pointer arithmetic makes use of the type being pointed to. Quoting the spec once again
[...] if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of
the array object, provided they exist.
Here, look at your construct:
((char*)a + m*i);
where m is the size of the actual object type pointed to by the actual argument. So, if you cast the pointer to the actual type, the calculation would be wrong. To present a comparison, say:
sizeof (char) is 1, mandated by standard.
sizeof (int) == 4 , say in your platform.
So, for an array int arr[ ] = {1, 2, 3, 4}, the expressions
(char*)a + (sizeof(int)*1)
and
(int*) a + 1
are equivalent.
Finally, touching the topic of converting another type of pointer to char* and accessing it:
[...] When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object. [....]
You need the char * cast because you do pointer arithmetic on the pointer, to get a byte offset from the beginning, but you can't do that on a void *.
A void pointer doesn't have a type size, so you can't calculate with it.
public:
int num=0;
int c;
int doubleToChar(double a){
while ((a-1)>=0){
num++;
}
c=a;
return a*10;
}/* int doubleToCharhundred(double a){
while ((a-1)>=0){
num++;
}
return a*100-c;
}*/
double a=12.12345;
char *tenDivide ;
char *intPart;
//u can add hundred or thousand by another char;
tenDivide =doubleToChar(a);
if(num<128)
intPart=num;
else{
while(num-1){
//same doubleToChar
}
}
Related
Need to implement one api which has some parameters;which has input's type (const void*), output's type (void**); the api wants to assign input with some offset to the output; for example,
void getOffset(const void* a, void** b)
{
int offset = getsomeoffset();
*b = a + offset;
}
This will have some complain in the compiler. What's the correct way to write this code? The input's type can be float, int, double.
You cannot apply pointer arithmetics on a void * pointer. The target pointed to does not have any type and hence no size which could be used to calculate the offset.
Therefore you need to cast your pointer before applying the offset:
*b = ((char *)a) + offset;
With this statement the offset is interpreted as number of bytes.
The problem here is the offset. A void has no size, so C does not allow pointer arithmetics on void *. Assuming that you want to use byte addresses, you should pass through char * arithmetics:
void getOffset(const void* a, void** b)
{
int offset = getsomeoffset();
char *p = a; // automatic conversion from void * to char *
p += offset; // char pointer arithmetics
*b = p; // automatic conversion for char * to void *
// or directly: *b = ((char *) a) + offset;
}
Given void *a, a + offset violates 6.5.6 Additive operators, paragraph 8 of the C standard:
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough...
A void * doesn't have a type, and it can't point to an actual object.
As others have noted, you have to cast the void * to another type, most likely char * would be appropriate.
I wrote a simple recursive function for binary search that takes three arguments: an array of integers, the length of the array and a value to find. The idea is that at every recursive call it either halves the length and keeps the array[0] in place or moves the starting index to the middle (third line from the bottom in my sample). That is until the value is found or length is 0.
Then I saw this disccussion: How do you shift the starting index of an array in C?
It is said here that an array name is a constant and cannot be reassigned in C. So my question is why this code works?
int rsearch( int needle, int haystack[], int size ) {
if (size == 0) {
printf("%i not found\n", needle);
return 0;
}
int mid = size / 2;
if (haystack[mid] == needle) {
printf( "found %i in the array\n", needle );
return 1;
} else if (haystack[mid] > needle) {
return rsearch( needle, haystack, size / 2 );
} else {
haystack = &haystack[mid + 1];
return rsearch( needle, haystack, (size - 1) / 2 );
}
I'm just studying, and my knowledge of pointers is very limited. And there's no practical application here. Just curious.
P.S.
The other question is what happens to the memory allocated to the original array when it's reduced this way? Is it made available again or is it a memory leak?
Arrays when used as function arguments actually mean a pointer to an array, but not the array as value. So the following function signatures are equivalent: void test(int xptr[10]), void test(int xptr[]), and void test(int *xptr).
At the point where an array is defined, however, you can only initialise it's value, but you cannot assign any other value later on.
When you pass an array, let's say int x[10] to a function by just using x as parameter, like in test(x), then array x automatically decays to a pointer to the first element of x.
See the following code showing the difference:
#include <stdio.h>
void test(int xptr[10]) {
printf("value of xptr[0]: %d\n", xptr[0]); // -> 0
xptr = &xptr[2]; // OK; xptr will point to element 2
printf("value of xptr[0]: %d\n", xptr[0]); // -> 2
}
int main(){
int x[10] = { 0,1,2,3,4,5,6,7,8,9 };
// x = &x[2]; // Error: Array type 'int [10]' is not assignable
// but:
test(x); // OK; and is eqivalent to...
test (&x[0]); // OK;
return 0;
}
As a function argument, this:
int haystack[]
Is equivalent to:
int *haystack
This is mainly because an array decays to a pointer to the first element when passed to a function.
So what you have is not an array but a pointer. Unlike an array, a pointer is a modifiable lvalue, so it is allowed to assign to it.
According to the C Standard (6.7.6.3 Function declarators (including prototypes))
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’...
and (6.3.2.1 Lvalues, arrays, and function designators)
3 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 and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
Thus in this function declaration
int rsearch( int needle, int haystack[], int size );
the parameter int haystack[] is adjusted to int *haystack. So these function declarations
int rsearch( int needle, int haystack[100], int size );
int rsearch( int needle, int haystack[10], int size );
int rsearch( int needle, int haystack[], int size );
int rsearch( int needle, int *haystack, int size );
declare the same one function. You may include all these declarations in your program because a function declaration may appear more than one time. However the function shall be defined only one time (if it is not an inline function).
Accordingly the array passed to the function as argument is implicitly converted to pointer to its first element.
Take into account that it would be better to declare the function like
int rsearch( int needle, const int *haystack, int size );
^^^^^
In this case the function can be used also with constant arrays.
It is said here that an array name is a constant and cannot be
reassigned in C.
It would be correctly to say that array is not a modifiable lvalue.
From the C Standard (6.5.16 Assignment operators)
2 An assignment operator shall have a modifiable lvalue as its left
operand.
and (6.3.2.1 Lvalues, arrays, and function designators)
...A modifiable lvalue is an lvalue that does not have array type,...
I was reading through some lecture notes that in order for a pointer to reference a 2D array, it has to be given the address of the first element.
int a[10][10];
int *p = &a[0][0];
I've never tried this, so I was curious why isn't it enough to assign the array itself to the pointer, just as we do in a 1D case.
int a[10][10];
int *p = a;
The array is kept in an uninterrupted 'line' of memory anyway, and 2D arrays only have a different type, but the same structure as 1D arrays.
By doing this
int *p = &a[0][0];
I don't see how we give the pointer any more information than by doing this
int *p = a;
Or maybe all arrays regardless of their number of dimensions have the same type, the only difference being that multidimensional arrays store their extra dimensions before their first element and we need to jump over those memory spaces which remember sizes of an array's dimensions?
First, some background:
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
Given the declaration
int a[10][10];
the expression a has type "10-element array of 10-element array of int". Unless this expression is the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 10-element array of int", or int (*)[10].
Given that declaration, all of the following are true:
Expression Type Decays to
---------- ---- ---------
a int [10][10] int (*)[10]
&a int (*)[10][10]
*a int [10] int *
a[i] int [10] int *
&a[i] int (*)[10]
*a[i] int
a[i][j] int
&a[i][j] int *
Also,
sizeof a == sizeof (int) * 10 * 10
sizeof &a == sizeof (int (*)[10][10])
sizeof *a == sizeof (int) * 10
sizeof a[i] == sizeof (int) * 10
sizeof &a[i] == sizeof (int (*)[10] )
sizeof *a[i] == sizeif (int)
sizeof a[i][j] == sizeof (int)
sizeof &a[i][j] == sizeof (int *)
Note that the different pointer types int (*)[10][10], int (*)[10], and int * don't have to be the same size or have the same representation, although on the platforms I'm familiar with they do.
The address of the first element of the array is the same as the address of the array itself; thus, all of a, &a, a[0], &a[0], and &a[0][0] will yield the same value, but the types will be different (as shown in the table above).
So, assume we add the following declarations:
int *p0 = &a[0][0]; // equivalent to int *p0 = a[0];
int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;
All of p0, p1, and p2 initially have the same value, which is the address of the first element in a; however, because of the different pointer types, the results operations involving pointer arithmetic will be different. The expression p0 + 1 will yield the address of the next int object (&a[0][1]). The expression p1 + 1 will yield the address of the next 10-element array of int (&a[1][0]). And finally, the expression p2 + 1 will yield the address of the next 10-element array of 10-element array of int (effectively, &a[11][0]).
Note the types of p1 and p2; neither is a simple int *, because the expressions being used to initialize them are not that type (refer to the first table).
Note the pattern; for an array type, the simpler the expression, the more complicated the corresponding type will be. The expression a does not refer to a single int object; it refers to a 10x10 array of int objects, so when it appears in an expression, it is treated as a pointer to an array of integers, not a pointer to a single integer.
The compiler knows that "a" is a pointer to ten integers. If you don't declare the dimensions, then the compiler sees the new pointer as a pointer to an unknown number of integers. This will work in your case, but it will generate a compiler warning because the compiler sees them as incompatible pointers. The syntax for what you are trying to do (without generating a compiler warning) is:
int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);
One reason this is important is pointer arithmetic:
p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes
You understanding is close, the difference is the type information. Pointer does has its type. For example int* p, the pointer type is int*, as int a[10][10], the corresponding pointer type is int *[10][10].
In your example, p and a do point to the same address, but they're different type, which matters when perform arithmetic operation on them.
Here's an example from this URL
Suppose now that we define three pointers :
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000, respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong;
mychar, as one would expect, would contain the value 1001. But not so obviously, myshort would contain the value 2002, and mylong would contain 3004, even though they have each been incremented only once. The reason is that, when adding one to a pointer, the pointer is made to point to the following element of the same type, and, therefore, the size in bytes of the type it points to is added to the pointer.
You are right, you can assign the array itself to the pointer:
int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};
int *p, *q, *r, *s;
p = &a[0][0];
q = a; // what you are saying
r = &b[0][0][0];
s = b; // what you are saying
printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);
printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);
And the output is:
p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8
They point to the same address, regardless of the dimension of the matrix. So, what you are saying is right.
Well in 2D array, the outcome of *a and a is the same, they all point to the first address of this 2D array!
But if you want to define a pointer to point to this array, you could use int (*ptr)[10] for example.
You are right, 1D and 2D share the same structure, but 2D has some additional manipulation on pointers like above.
So all in all, in 2D array, a, *a and &a[0][0] prints the same address, but their usages may vary.
Like this:
#include<stdio.h>
int main() {
int a[10][10];
int *pa1 = &a[0][0];
int *pa2 = *a;
printf("pa1 is %p\n", pa1);
printf("pa2 is %p\n", pa2);
printf("Address of a is %p\n", a);
// pointer to array
int (*pa3)[10];
pa3 = a;
printf("pa3 is %p\n", pa3);
return 0;
}
They print the same address.
i had a question in my program. When I pass the 3D int array CodedGreen to the function Green_Decode_Tree. An error message"invalid use of array with unspecified bounds" displayed. What is the mistake in my program? Thanks for your help.
for(i=0;i<256;i++){
for(j=0;j<256;j++){
Decode_Tree(green[0], CodedGreen,0,i,j);
}
}
void Green_Decode_Tree(node* tree, int code[][][], int num,int row,int col)
{
int i;
i=num;
if((tree->left == NULL) && (tree->right == NULL)){
fprintf(DecodGreen,"%s\n", tree->ch);
}
else
{
if(code[row][col][num]==1){
i++;
Green_Decode_Tree(tree->left,code,i,row,col);
}
else if (code[row][col][num]==0){
i++;
Green_Decode_Tree(tree->right,code,i,row,col);
}
}
}
i will reveal you a secret. 2d (and 3d) arrays are represented as liner memory arrays. when you have array NxM and access it like a[i][j] it is actually translated to a[i*M + j] as you might notice compiler must know M here to do this conversion, otherwise it will not be able to translate it. So thats what he asks. You must provide all except first sizes in array: int code[][M][N]
Remember that in most contexts, array expressions have their types implicitly converted ("decay") from "N-element array of T" to "pointer to T" and evaluate to the address of the first element. When you pass CodedGreen (type int [X][Y][Z]) to Green_Decode_Tree, what the function receives is a pointer value of type int (*)[Y][Z].
So your prototype for Green_Decode_Tree needs to be
void Green_Decode_Tree(node *tree, int (*code)[Y][Z], int num, int row, int col)
Note that in the context of a function parameter declaration, int *a is synonymous with int a[] (no size), so int (*code)[Y][Z] could also be written as int code[][Y][Z]. I prefer using pointer notation, since that's what the function actually receives, but either will work. Note that in your function you will subscript it as normal:
if (code[row][num][col] == 1)
since the subscript operator implicitly dereferences the pointer (i.e., code[row] == *(code+row)).
This may be helpful:
Declaration Expression Type Decays to
----------- ---------- ---- ---------
T a[X]; a T [X] T *
&a T (*)[X]
T b[X][Y]; b T [X][Y] T (*)[Y]
&b T (*)[X][Y]
b[i] T [Y] T *
&b[i] T (*)[Y]
T c[X][Y][Z]; c T [X][Y][Z] T (*)[Y][Z]
&c T (*)[X][Y][Z]
c[i] T [Y][Z] T (*)[Z]
&c[i] T (*)[Y][Z]
c[i][j] T [Z] T *
The expressions a, b, b[i], c, c[i], and c[i][j] are all array expressions, so their types will decay to pointer types in most contexts. The exceptions are when the array expressions are operands of the sizeof or address-of & operators (as is shown in the table), or when the array expression is a string literal being used to initialize another array in a declaration.
I would like to know if there is any way to return an char array.
I tried something like this "char[] fun()" but I am getting error.
I don't want a pointer solution.
Thanks!
You can return an array by wrapping it in a struct:
struct S {
char a[100];
};
struct S f() {
struct S s;
strcpy( s.a, "foobar" );
return s;
}
Arrays cannot be passed or returned by value in C.
You will need to either accept a pointer and a size for a buffer to store your results, or you will have to return a different type, such as a pointer. The former is often preferred, but doesn't always fit.
C functions cannot return array types. Function return types can be anything other than "array of T" or "function returning T". Note also that you cannot assign array types; i.e., code like the following won't work:
int a[10];
a = foo();
Arrays in C are treated differently than other types; in most contexts, the type of an array expression is implicitly converted ("decays") from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression is an operand of either the sizeof or address-of (&) operators, or when the expression is a string literal being used to initialize another array in a declaration.
Given the declaration
T a[N];
for any type T, then the following are true:
Expression Type Decays to Notes
---------- ---- --------- -----
a T [N] T * Value is address of first element
&a T (*)[N] n/a Value is address of array (which
is the same as the address of the
first element, but the types are
different)
sizeof a size_t n/a Number of bytes (chars) in array =
N * sizeof(T)
sizeof a[i] size_t n/a Number of bytes in single element =
sizeof(T)
a[i] T n/a Value of i'th element
&a[i] T * n/a Address of i'th element
Because of the implicit conversion rule, when you pass an array argument to a function, what the function receives is a pointer value, not an array value:
int a[10];
...
foo(a);
...
void foo(int *a)
{
// do something with a
}
Note also that doing something like
int *foo(void)
{
int arr[N];
...
return arr;
}
doesn't work; one the function exits, the array arr technically no longer exists, and its contents may be overwritten before you get a chance to use it.
If you are not dynamically allocating buffers, your best bet is to pass the arrays you want to modify as arguments to the function, along with their size (since the function only receives a pointer value, it cannot tell how big the array is):
int a[10];
init(a, sizeof a / sizeof a[0]); // divide the total number of bytes in
... // in the array by the number of bytes
void init(int *a, size_t len) // a single element to get the number
{ // of elements
size_t i;
for (i = 0; i < len; i++)
a[i] = i;
}
arrays aren't 1st class objects in C, you have to deal with them via pointers, if the array is created in your function you will also have to ensure its on the heap and the caller cleans up the memory
A Very very basic code and very very basic explanation HOW TO Return
array back from a user defined function to main function..Hope It
helps!! Below I have given complete code to make any one understand
how exactly it works? :) :)
#include<iostream>
using namespace std;
char * function_Random()
{
int i;
char arr[2];
char j=65;//an ascII value 65=A and 66=B
cout<<"We are Inside FunctionRandom"<<endl;
for(i=0;i<2;i++)
{
arr[i]=j++;// first arr[0]=65=A and then 66=B
cout<<"\t"<<arr[i];
}
cout<<endl<<endl;
return arr;
}
int main()
{
char *arrptr;
arrptr=function_Random();
cout<<"We are Inside Main"<<endl;
for(int j=0;j<2;j++)
{
cout<<"\t"<<arrptr[j];
}
return 0;
}