Changing to Pointer Arithmetic

2020-05-07 18:02发布

I'm new to pointers in C and I'm having a lot of trouble figuring out how to work with them.

I have this piece of code with some pointer arithmetic inside a void function:

void function(int n, int *a, int *b){
   int *p,*q;
   q = b;
   int i;
   *b = 0;

    for (i = 1; i<n; i++)
       if(*(a+i) == *(a+i-1))
          *(b+i)=0;
       else
          *(b+i)=1;
}

I'm trying to change it completely to use only pointer arithmetic with no loop index variables. So far I've gotten this:

void function(int n, int *a, int *b){
   int *p,*q;
   q = b;
   *b = 0;

    for (p = a+1; p<a+n; p++)
       if(*a == *a-1)
          *b=0;
       else
          *b=1;
}

But to my understanding isn't it exactly the same as the first piece of code above? Am I missing something? Thanks for your help

3条回答
Animai°情兽
2楼-- · 2020-05-07 18:44

Your program have some unused variables. Don't ignore the compiler's warning.

Here is what I guess you mean:

void function0(int n, int *a, int *b)
{
    b[0] = 0;
    int i;
    for (i = 1; i < n; i++)
        if(a[i] == a[i-1])
            b[i] = 0;
        else
            b[i] = 1;
}

function0() is syntactically identical to

void function1(int n, int *a, int *b)
{
    *b = 0;
    int i;
    for (i = 1; i < n; i++)
        if(*(a + i) == *(a + i - 1))
            *(b + i) = 0;
        else
            *(b + i) = 1;
}

which is functionally identical to:

void function2(int n, int *a, int *b)
{
    *b = 0;
    int *p, *q;
    for (p = a + 1, q = b; p < a + n; p++, q++)
        if(*p == *(p - 1))
            *q = 0;
        else
            *q = 1;
}
查看更多
爷的心禁止访问
3楼-- · 2020-05-07 18:54

If you are struggling with pointers a bit, the short version of how to understand a pointer is to understand it is simply a variable that holds an address to something else as its value. Take a normal variable int x = 5; where x contains the immediate-value 5.

A pointer on the other-hand, does not contain an immediate-value, but contains the address where an immediate-value (or another pointer) can be found in memory. This provides quite a bit of increased flexibility in how you use pointers. Just as you can use arithmetic on x (e.g. x++;) to increment 5 -> 6, when you increment a pointer to an array, the pointer now points to the next address in the array.

So if you have declared int a[] = {3, 5, 7, 9};, you would have the following relationships regarding a among the sequential block of memory allocated as storage for a:

 a    m1  m2  m3  m4    /* points to memory locations m1 -> m4 */
    | 0 | 1 | 2 | 3 |   /* the zero based array indexes        */
    | 3 | 5 | 7 | 9 |   /* the values stored in m1 -> m4       */

You desire to eliminate working with the array indexes 0-4 and perform the same manipulations in function using only the memory address location information and their values. This is where pointer-arithmetic can be used just like array indexing to set, compare, remove values from your array. When iterating an array using a pointer, you generally will declare a pointer to use for iteration purposes so you do not lose the start address for your block of memory.

Thankfully when pointers (or arrays due to conversion) are passed as arguments to a function, the function receives a copy of the pointer and not the original address for the pointer in the calling function. You still may need to save a pointer holding the original address for the copy, but that just depends on what you need to do in the function.

If you want to re-implement the same logic in function incrementing pointers instead of incrementing an index 'i', then you will need to handle the increment of the first pointer position in both a and b when you set your default *b=0;. While you can simply skip over the first character in each using indexes by iterating for (i = 1;..., you must increment the pointers themselves if you take that approach. You can handle that within the loop by simply skipping the iteration where a holds its original address:

void functionp (int n, int *a, int *b)
{
int *p = a;  /* saved the original value of the copy */
*b = 0;

    for (; a < p + n; a++, b++)
        if (a > p)
            *b = (*a == *(a - 1)) ? 0 : 1;
        else
            continue;  /* skip first loop where 'p == a' */
}

Or, you can preincrement both a and b before starting the loop (e.g. a++, b++;) to insure your are addressing the second and first characters in a in your if statement. An example there would be:

void functionp (int n, int *a, int *b)
{
int *p = a;  /* saved the original value of the copy */
*b = 0;

    a++, b++;  /* increment both 'a' and 'b' */
    for (; a < p + n; a++, b++)
        *b = (*a == *(a - 1)) ? 0 : 1;
}

Since you seem to have a fair handle on the dereferencing aspect of pointers to operate on the value pointed to in memory, I'll leave that to you. A short comparison example allows you to run the code without argument (or with argument not beginning with 'f') to see the results of your original function on the array, or providing an arguments that begins with 'f' will call the pointer use function:

#include <stdio.h>

void function (int n, int *a, int *b);
void functionp (int n, int *a, int *b);

int main (int argc, char **argv) {

    int a[] = {1,1,2,2,3,3,3,4};
    int i, n = sizeof a/sizeof *a;
    int b[n];

    if (argc > 1 && *argv[1] == 'f') {
        printf ("\n executing 'function'\n\n");
        function (n, a, b);
    }
    else {
        printf ("\n executing 'functionp'\n\n");
        functionp (n, a, b);
    }
    for (i = 0; i < n; i++)
        printf (" a[%d] : %d | b[%d] : %d\n", 
                i, a[i], i, b[i]);

    return 0;
}

void function (int n, int *a, int *b)  /* original function */
{
int i;
*b = 0;

    for (i = 1; i < n; i++)
    if(*(a+i) == *(a+i-1))
        *(b+i)=0;
    else
        *(b+i)=1;
}

void functionp (int n, int *a, int *b) /* pointer use only function */
{
int *p = a;
*b = 0;

    a++, b++;  /* increment both 'a' and 'b' */
    for (; a < p + n; a++, b++)
        *b = (*a == *(a - 1)) ? 0 : 1;
}

Example Use/Output

$ ./bin/idx2ptr f

 executing 'function'

 a[0] : 1 | b[0] : 0
 a[1] : 1 | b[1] : 0
 a[2] : 2 | b[2] : 1
 a[3] : 2 | b[3] : 0
 a[4] : 3 | b[4] : 1
 a[5] : 3 | b[5] : 0
 a[6] : 3 | b[6] : 0
 a[7] : 4 | b[7] : 1


$ ./bin/idx2ptr p

 executing 'functionp'

 a[0] : 1 | b[0] : 0
 a[1] : 1 | b[1] : 0
 a[2] : 2 | b[2] : 1
 a[3] : 2 | b[3] : 0
 a[4] : 3 | b[4] : 1
 a[5] : 3 | b[5] : 0
 a[6] : 3 | b[6] : 0
 a[7] : 4 | b[7] : 1

Look over the function and the example and let me know if you have any questions. I hope this helps.

查看更多
唯我独甜
4楼-- · 2020-05-07 18:57

They are not the same, you have to substitute a with p in the for body and use the q pointer to modify b.

void function(int n, int *a, int *b)
{
   *b = 0;
    for (int *p = a + 1, *q = b ; p < a + n ; ++p, ++q)
    {
       if (*p == *(p - 1))
          *q = 0;
       else
          *q = 1;
    }
}
查看更多
登录 后发表回答