Pointer issue in C - c

Greetings,
I am trying to learn pointers in C, I simply want my "addtwo" function to add 2 to every element of the input integer array, yet I get odd compilation errors, here is the non-pointer version which indeed won't properly compile.
addtwo(int *arr[]) {
int i=0;
for(;i< sizeof(arr)/sizeof(int);i++) {
arr[i] = arr[i] + 2;
}
}
main() {
int myarray[] = {1,2,3,4};
addtwo(myarray);
}
Regards

You've some problems. First, you try to pass a int* to a parameter that's type int**. That won't work. Give it type int*:
void addtwo(int *arr){
int i=0;
for(;i< sizeof(arr)/sizeof(int);i++){
arr[i] = arr[i] + 2;
}
}
Then, you need to pass the size in an additional argument. The problem is, that when you pass arrays, you really pass just a pointer (the compiler will make up a temporary pointer that points to the array's first element). So you need to keep track of the size yourself:
void addtwo(int *arr, int size){
int i=0;
for(;i<size;i++){
arr[i] = arr[i] + 2;
}
}
int main(void) {
int myarray[] = {1,2,3,4};
addtwo(myarray, sizeof myarray / sizeof myarray[0]);
}
Now it will work. Also put the return type before them. Some compilers may reject your code, since it doesn't comply to the most recent C Standard anymore, and has long been deprecated (omitting the return type was the way you coded with the old K&R C).

addtwo(int *arr[]) should be addtwo(int *arr)
You cannot use sizeof to get the size of an array from a pointer. Typically you would either pass the size of the array as a separate arg or have some special value marking the last element.

Not to do with the compile error, but...
You have to pass sizeof(arr) to the function instead of calling it in the function. When an array is passed to a function, C no longer sees it as an array, but as a single pointer to memory, so that sizeof(arr) as you are calling it now, will return the size of the pointer arr, which is most likely 4.
Here's what I mean in code:
void addtwo(int *arr, int size){
int i=0;
for(;i< size;i++){
arr[i] = arr[i] + 2;
}
}
int main(){
int myarray[] = {1,2,3,4};
addtwo(myarray, sizeof(arr)/sizeof(int));
return 0;
}

In C a notation int *arr[] is the same as int** arr.

You need to pass a pointer to the first element of the array and the array size. Array types decay to pointers in the context of function parameters. Try:
void addtwo(int *arr, size_t size){
for(size_t i = 0; i < size; i++){
arr[i] = arr[i] + 2;
}
}
int main() {
int v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
addtwo(v, sizeof v / sizeof v[ 0 ]);
return 0;
}

Though others already gave the correct response, basically you have an array of pointers when you have
int *arr[]
I doubt that is what you want. If you have
int arr[]
then that will also be equivalent to
int *arr

addtwo argument declaration really reads:
arr is an array of pointers to integer
when you probably really want
a pointer to an array of integers
"How to Read C Declarations" has really helped me to grok the topic a while ago, maybe it will do the same for you.

Related

Regarding question about function pointer in C?

I was reading about function pointer. That it contains address of instructions. And there I encountered one question to find an element in array using function pointer. Here is the code.
#include <stdio.h>
#include <stdbool.h>
bool compare(const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(void* arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = (char*)arr; // Here why not int *ptr = (int*)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
In the search function char *ptr = (char*)arr; is used which is giving perfect answer = 2.
But when I have used int *ptr = (int*)arr; it gives -1 as answer.
Why is this? Can anyone explain this?
A char is the smallest addressable unit in any C program, and on most system it corresponds to a single byte. That treats the array as a generic sequence of bytes, and uses the ele_size to calculate the byte-position of each element with ptr + i*ele_size.
If you use int *ptr then the byte-position calculation will be wrong by a factor of sizeof(int) (typically 4), since the pointer arithmetic will be done in units of the base type (int instead of char).
The function search knows nothing about what is the type of elements of the array pointed to by the pointer arr of the type void *.
So casting the pointer to the type int * does not make a sense. If to do so then the expression ptr + i*ele_size where the pointer arithmetic is used will produce an incorrect result.
That it contains address of instructions
There is a subtle difference between normal (object) pointers and function pointers. It is not possible to access the single instructions of a function - they do not have the same length.
With other pointers the increment (arithmetic) is adapted to the type, whether as p[i] or p + i or *(p+i).
Side note: there still is int at the bottom of the call chain:
return (*(int*)a == *(int*)b);

what's *p when p is declared as int (*)[size] and assigned to an array

code:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
result: p = *p = arr = 0x7ffee517c830 they are all the address of the array
The right way to use p to visit arr[i] is *(*p+i)
The type of pointer p is int(*)[5], so p point to an array which type is int [5]. But we can't say that p point to an invisible shell of arr, p is a variable after all. It stores the address of arr, which is also the address of arr[0], the first element of arr.
I thought *p will get me 1, which is the first element of arr.
The dereference operation means take the value in p as address and get the value from this address. Right?
So p stores the address of arr,which is 0x7ffee517c830 here, and 1 is stored in this address. Isn't **p illegal? The first dereference give us 1, and second dereference will use 1 as address which is illegal.
What I am missing?
The result of *p is an lvalue expression of array type. Using (*p) is exactly the same as using arr in any expression you could now think of.
For example:
&*p means &arr
**p means *arr (which is legal).
(*p)[i] means arr[i].
sizeof *p means sizeof arr.
Arrays are not special in this regard. You can see the same phenomenon with int x; int *q = &x;. Now *q and x have exactly the same meaning.
Regarding your last paragraph, I think you are confusing yourself by imagining pointers as glorified integers. Some people teach pointers this way but IMO it is not a good teaching technique because it causes the exact confusing you are now having.
If you dereference an int(*)[5] you get an int[5] and that's all there is to it. The data type matters in dereferencing. It does not make sense to talk about "dereferencing 0x7ffee517c830". Again this is not peculiar to arrays; if you dereference a char ***, you get a char ** etc.
The only way in which arrays are "different" in this discussion is what happens if you try to do arithmetic on them, or output them, etc. If you supply an int[5] as a printf argument for example, there is implicit conversion to int * pointing at the first of those 5 ints. This conversion also happens when applying the * operator to an int[5], which is why you get an int out of that.
p is declared as a 'pointer to int[5]'.
arr is declared as an 'int[5]`
so the initializer p = &arr; is not really that strange. If you substituted any primitive type for int[5] you wouldn't bat an eye.
*p is another handle on arr. so (*p)[0] = 1.
This really only comes up in wierd cases. It's most natural where you dereference the pointer-to-array using the subscript operator. Here's a contrived example where I want to pass a table as argument.
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
This example treats the table as an array of rows.
Dereferencing doesn't give you a value. It gives you an object, which can be used as a value of its type if it can be converted to.
*p, being identical to arr, is an object of an array of 5 ints, so if you want to get an integer from the array, you must dereference it again like (*p)[3].
Consider a bigger example:
int arr[5][5];
int (*p)[5] = arr;
Now you get arr[0] with *p, which itself is an array of 5. Here comes the difference:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
Got the point?
One use case is to be able to allocate with malloc an 2D (or more) pointer of arrays with only one malloc:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I think this very funny.
One more with VLA:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}

Find max element in a matrix [duplicate]

This question already has answers here:
How to pass 2D array (matrix) in a function in C?
(4 answers)
Closed 6 years ago.
I've got this homework. Basically, what I have to do is complete the following code that returns the maximum element of a bidimensional array of 'r' rows and 'n' columns.
#include <stdio.h>
int max_element(int **A, int r, int n) {
// complete the code
int max;
max = a[0][0];
for (int i = 0; i < r; i++) {
for (int j = 0; j < n; j++) {
if (A[i][j] > max)
max = A[i][j];
}
}
return max; }
// implement a main() function to test the algorithm
int main() {
int A[2][3] = { {1, 0, 4}, {10, 3, 1} };
printf("%d\n", max_element(&A, 2, 3));
return 0; }
I have 1 warning:
passing argument 1 of 'max_element' from incompatible pointer type [-Wincompatible-pointer-types]
The console stopped working: a problem caused the program to stop working correctly...
Your max_element function is defined as such:
int max_element(int **A, int r, int n);
It takes a pointer to a pointer to int (int**) and you are feeding it this:
int A[2][3];
max_element(&A, 2, 3);
Do you expect the expression &A to yield a result of type int**? It will not. It will in fact yield a result of type int(*)[2][3]. That will not bind to int**. This is where the compiler warning kicks in. Those are incompatible pointers!!
You have a wider problem though. A 2D array is not int**. It has type int[][COLS]. You must specify the second number.
Change your function to be:
const int COLS = 3;
int max_element(int A[][COLS], int r, int n);
and then call as:
max_element(A, 2, 3);
Change the function prototype of max_element from:
int max_element(int **A, int r, int n)
To
int max_element(int A[][3], int r, int n)
This C-Faq thoroughly explains why. The gist of it is that arrays decay into pointers once, it doesn't happen recursively. An array of arrays decays into a pointer to an array, not into a pointer to a pointer.
And also, you should call max_element by max_element(A, 2, 3) instead of max_element(&A, 2, 3).
If a function is already declared as accepting a pointer to a pointer (as in your case), it is almost certainly meaningless to pass a two-dimensional array directly to it. An intermediate pointer would have to be used when attempting to call it with a two-dimensional array:
int max_element(int **A, int r, int n);
int *ip = &A[0][0];
max_element(&ip, 2, 3); /* PROBABLY WRONG */
but this usage is misleading and almost certainly incorrect, since the array has been flattened (its shape has been lost).

C - Void pointer and offset

Say I have a void pointer (more like; array), and I want to get the items inside it.
So, I know that pointer[i] won't work since it's void and I don't know the type; I tried using the offset technique:
void function(void* p, int eltSize){
int offset = 3;
for(i = 0; i<offset; i++){
memcpy(p+(i*eltsize), otherPointer, eltSize);//OtherPointer has same type.
}
//End function
}
This function works good and everything, but the only problem is that at the end of main(..) I get segmentation fault. I know it's because of the pointer and how I accessed the items of it, but I don't know how to correct the problem and avoid segmentation fault.
As pointed out by #sunqingyao and #flutter, you can not use arithmetic with void pointers in Standard C; instead, use a char * (a chunk of bytes a la qsort):
#include <stdio.h>
#include <string.h>
void function(void *ptr, size_t eltSize, void *otherPointer, size_t offset)
{
char *p = ptr;
for (size_t i = 0; i < offset; i++) {
memcpy(p + (i * eltSize), otherPointer, eltSize);
}
}
int main(void)
{
int arr[] = {1, 2, 3};
int otherValue = 4;
function(arr, sizeof *arr, &otherValue, sizeof arr / sizeof *arr);
for (int i = 0; i < 3; i++) {
printf("%d\n", arr[i]);
}
return 0;
}
Quoted from N1570 6.5.6 Additive operators(emphasis mine):
2 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. (Incrementing is equivalent to adding
1.)
Obviously, void isn't a complete object type. Thus, applying + operator on void * invokes undefined behaviour, which may result in segmentation fault or anything else.
One approach to solve your problem would be declaring parameter p as a char *.

Generic insertion sort in C

I have coded a generic insertion sort in C, and it works really fine.
But, On my function of insertion sort, it gets a void** arr,
and on its signature it gets a void* arr, otherwise, it doesn't work.
Why is it so?
Do we have any other ways to code the insertion sort to be generic?
The Full code is here:
#include <stdio.h>
#include <malloc.h>
#define SIZE 10
int cmp(void* elm1, void* elm2);
void insertionSort(void* arr, int size);
int main()
{
int arr[] = {5, 8, 2, 3, 15, 7, 4, 9, 20, 13};
int arr2[] = {1};
int i;
for (i = 0; i < SIZE; i++)
printf("%d ", arr[i]);
printf("\n");
insertionSort(&arr, SIZE);
for (i = 0; i < SIZE; i++)
printf("%d ", arr[i]);
return 0;
}
void insertionSort(void** arr, int size)
{
int i = 1;
int j;
void* temp;
while (i < size)
{
if (cmp(arr[i], arr[i-1]) == -1)
{
temp = arr[i];
j = i - 1;
while (j >= 0 && cmp(arr[j], temp) == 1)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
i++;
}
}
int cmp(void* elm1, void* elm2)
{
if ((int)elm1 == (int)elm2)
return 0;
else if ((int)elm1 > (int)elm2)
return 1;
else
return -1;
}
The code as it is, is undefined, because of multiple problems. It just happens to work, because on your system the size of the pointer is the same as the size of the type int.
You code will not compile without warnings (if you enable them). The function insertionSort and it's prototype must have the same type.
You should change the type in the function definition to
void insertionSort(void* arr, int size)
And then cast the pointer arr, to an appropriate type. Since this is a generic sort, like qsort(), the only realistic option is a cast to char*. This means you will also have to pass the size of the type into the function, so the pointer can be incremented correctly. This will require you to change the function drastically.
So, the function prototype should really be the same as qsort:
void Sort(void* arr, size_t size , size_t object_size , int(*)( const void* , const void* ))
The problem is that integers are not pointers, so your test array is of type *int or int[]. But in your function, you don't know that and you try to make your code work with pointers. So you expect * void[]. If you change your temp variable to int, you don't need the ** in the signature. The same way, if you want to keep the "generic" (as you call), you need an array of *int.
Basically, in C you cannot write a function working out of the box for both primary types and pointers. You need some tricks. Have a look at this stackoverflow, maybe it will help.

Resources