Изменение адреса, содержащегося в указателе, с помощью функции

#c #list #file #pointers

Вопрос:

Если я объявил указатель p как int *p ; в главном модуле, я могу изменить содержащийся в нем адрес p , назначив p = amp;a; , где a уже объявлена другая целочисленная переменная. Теперь я хочу изменить адрес, используя функцию как:

 void change_adrs(int*q)
{
    int *newad;
    q = newad;
}
 

Если я вызову эту функцию из основного модуля

 int main()
{
    int *p;
    int a = 0;
    p = amp;a; // this changes the address contained by pointer p
    printf("The address is %un", p);
    change_adrs(p);
    printf("The address is %un", p); // but this doesn't change the address
    return 0;
}
 

содержимое адреса не изменилось. Что плохого в использовании функции для одной и той же задачи?

Комментарии:

1. Вы передаете указатель по значению. Если вам нужно изменить указатель внутри функции, передайте его по ссылке… двойной указатель.

Ответ №1:

В C аргументы функций передаются по значению. Таким образом, создается копия вашего аргумента, и изменение вносится в эту копию, а не в фактический объект указателя, который вы ожидаете увидеть измененным. Вам нужно будет изменить свою функцию, чтобы принять аргумент от указателя к указателю и внести изменения в разыменованный аргумент, если вы хотите это сделать. Например

  void foo(int** p) {
      *p = NULL;  /* set pointer to null */
 }
 void foo2(int* p) {
      p = NULL;  /* makes copy of p and copy is set to null*/
 }

 int main() {
     int* k;
     foo2(k);   /* k unchanged */
     foo(amp;k);   /* NOW k == NULL */
 }
 

Если у вас есть роскошь использовать C , альтернативным способом было бы изменить функцию, чтобы она принимала ссылку на указатель.

Комментарии:

1. Я просто хотел бы отметить, что стандарт C не гарантирует, что присвоение p 0 делает его нулевым.

2. Если бы я указал на *arr = malloc() новый массив в вызываемой функции и указал **p на него, так ли это *p = amp;arr ?

3. @JKRT: 6.2.3.2 в спецификации C говорится, что «Целочисленное постоянное выражение со значением 0 или такое выражение, приведенное к типу void*, называется константой указателя null». — поэтому назначение литерала 0 сделает его нулевым. «Или» в этом предложении означает, что приведение не требуется.

Ответ №2:

В C переменные передаются по значению — копия указателя передается функции. Вместо этого используйте другой указатель на указатель:

 void change(int **p, int *someOtherAddress)
{
    *p = someOtherAddress;
}

int a = 1, b = 2;
int *p = amp;a;

printf("*p = %dn", *p);
change(amp;p, amp;b);
printf("*p = %dn", *p);
 

Это печатает

 *p = 1
*p = 2
 

Комментарии:

1. Поднимите голос исключительно потому, что этот ответ позволяет избежать фразы «двойной указатель».

Ответ №3:

Если вы хотите изменить содержимое переменной в функции на языке Си, указатель также является своего рода переменной, вы должны передать его по указателю или косвенной ссылке, используя операторы всегда amp; адреса и * разыменования. Я имею * в виду, что оператор всегда используется и предшествует при изменении значения переменной.

 #include <stdio.h>
#include <stdlib.h>


void changeIntVal(int *x) {
    *x = 5;
}

void changePointerAddr(int **q) {
    int *newad;
    *q = newad;
}

void changePPAddr(int ***q) {
    int **dummy;
    *q = dummy;
}

int main() {
    int *p;
    int **pp;
    int *tempForPP;
    int a = 0;
    printf("n The address pointing by p -> %p, pp -> %p, value of a -> %d ", p, pp, a);


    p = amp;a;
    pp = amp;tempForPP;
    printf("n The address pointing by p -> %p, pp -> %p, value of a -> %d ", p, pp, a);

    changeIntVal(amp;a);        // ----
                             //    |---
    changePointerAddr(amp;p);   // ----  |---->  parts of what I mean
                             //    |---
    changePPAddr(amp;pp);       // ----

    printf("n The address pointing by p -> %p, pp -> %p, value of a -> %d ", p, pp, a);

    return 0;

}
 

Ответ №4:

Для примитивного типа данных , такого как an int , двойные указатели не нужны. Вы можете записать непосредственно в адрес, где int хранится, обрабатывая его адрес как указатель в вызываемой функции. Это не похоже на char массив («строка»), где размер того, на что указано, является переменным, и поэтому вы должны использовать другой уровень косвенности при изменении его внутри вызываемой функции. Попробуйте это:

 void foo(int *oldVal)
{
    int newVal = 99;    // or whatever you want
    *oldVal = newVal;
}

int main(int argc, char *argv[])
{
    int someVal = 0;
    foo(amp;someVal);      // we send its address to foo()

    printf("someVal is now %d.n", someVal);

    return EXIT_SUCCESS;
}
 

Комментарии:

1. Это не ответ на вопрос !, он просит изменить адрес указателя, а не значение указателя

Ответ №5:

Это не изменит фактическое значение p , потому q что функция in локальна для этого, и изменение в этой функции не отразится, main поэтому передайте адрес p вместо передачи p по значению

Используйте этот синтаксис ниже

 void change_adrs(int **q)
{
    int * otheraddess;
    *q = otheraddress; 
}
 

и позвонить вот так change_adrs(amp;p);

Или у вас есть другой способ: измените тип возвращаемой функции и поймайте возвращаемый адрес.

 int* change_adrs(int *q)
{
    int * otheraddess;
    q = otheraddress;
    return q; 
}


int main()
{
    p = change_adrs(p);
    return 0;
}