Если функции передать указатель должна произойти ошибка

Сообщество Программистов

Загрузка…

Токен &

В С++ этот токен имеет много значений:

  • Как бинарный оператор — оператор побитового «и».

    0b0011 & 0b0110; // 0b0010
    
  • Как унарный оператор — оператор взятия адреса у переменной.

    Type a;
    Type * ap = & a; // указатель на переменную типа Type
    
  • Как часть объвления типа — модификатора типа.

    Type & r; // ссылка на переменную типа Type
    

Токен *

Этот токен имеет такой же набор значений

  • Как бинарный оператор — оператор умножения.

    3 * 5; // 15
    
  • Как унарный оператор — оператор разыменовывания (взятие значения) переменной.

    Type a;
    Type & ar = * a; // ссылка на переменную типа Type
    
  • Как часть объвления типа — модификатора типа.

    Type * r; // указатель на переменную типа Type
    

Ссылки как значения

Работа с ссылками это как работа с их значениями.
Нельзя переопределить ссылку чтобы она указывала на другой объект.
Почти весь синтаксис для ссылки и для переменной значения одинаковый.
Ссылки обяъвляются как Type & name. И в дальнейшем ведут себя как обычные пермененые содержащие значение.

struct Type {
   int a;
}

Type o;
Type & r = o;

o.a = 1; // ok
r.a = 2; // ok

Переменную-ссылку можно присвоить обеъкту и наоборот:

Type & ref = o;
Type val;

ref = val;
val = ref;

Передача как аргумент функции тоже явлется присваиванием так что предыдущее верно и для них:

void fun1(Type x) {}
fun1(o); // ok
fun1(r); // ok

void fun2(Type & y) {}
fun2(o); // ok
fun2(r); // ok

Почему нельзя присвоить указатель ссылке.

Одна из наиболее важных причин для этого заключается в том, что указатель может содержать адрес не валидного объекта. Этот процесс отдан программистам:

void funcp(Type* p) {
    if (p == nullptr) {
        Type & r = &p; // Здесь ОС пошлет сигнал и программа аварийно завершится
    }
    else {
        Type & r = &p; // Здесь все должно быть хорошо
    }
} 

Также указатель можно переназначить, но в случае передачи указателя в функцию это не имеет значения.
Есть еще ряд других случаев когда ссылки и указатели служат совсем разным целям, но это повод для отедльной статьи.

Step on Stepik: https://stepik.org/lesson/567/step/3

Реализуйте функцию array_size, которая возвращает размер массива, переданного в качестве параметра. Функция должна работать только для массивов! Т. е. если функции передать указатель, должна произойти ошибка компиляции. Примеры:

int ints[] = {1, 2, 3, 4};int *iptr = ints;double doubles[] = {3.14};array_size(ints); // вернет 4array_size(doubles); // вернет 1array_size(iptr); // тут должна произойти ошибка компиляции

Hint: в одной из первых недель мы вам показывали трюк с передачей массивов только заданного размера в функцию (передача массива по ссылке), совместите его с вашими знаниями о шаблонах.

I have a bug in which an incorrect value gets passed as an argument to a function in a C program. The way it works is, I declare a static pointer to a typedef-ed data structure as a global variable. There is an initialization function where this variable is initialized. This function allocates memory, initializes data fields and returns the pointer. Something like this:

static my_type *my_ptr;
...
void init(void){
   my_ptr = init_my_type();
}

The function init_my_type is pretty straight forward:

void *init_my_type(void){
   my_type *x = malloc(sizeof(my_type);
   x->arg1 = 0;
   ... // more field initializations
   return x;
}

Later on I use my_ptr as an argument to another function:

void do_stuff(void){
   func(my_ptr);
}

The problem I have is that I seg fault in the guts of func when some of the data in the data structure that my_ptr points to is accessed.

When I run the debugger I get a nice looking hex value when I break on the init_my_type:

(gdb) finish
Value returned is $26 (void *) 0x79b6c0

Later, inside the do_stuff function, my_ptr has the same hex value:

(gdb) print my_ptr
$26 = (my_type *) 0x79b6c0

but, when I break on func the argument it gets has a totally different value.

Breakpoint 2, func(arg=0x1388)

I am type-punning pointers all over the place, but I don’t see that that should change the address in memory that they point to, right? Also, the function func is declared inline but why should that affect this? This all seems correct to me — it is entirely possible that I’m doing something stupid that I don’t see.

Here is a complete program of the simplified code. In reality, all these functions don’t get called by main, but by dynamically loaded helper functions. Still, I don’t see how the address pointed to by my_ptr should change when passed to func.

#include "stdlib.h"
#include "stdio.h"

typedef struct _type{
  int *i1;
  float *f1;
}my_type;

static my_type *my_ptr;

void *init_my_type(void){

  my_type *x = malloc(sizeof(my_type));
  x->f1 = malloc(sizeof(float));
  x->i1 = malloc(sizeof(int));
  x->f1[0] = 123.456;
  x->i1[0] = 789;

  return x;

}

void init(void){

  my_ptr = init_my_type();

}

inline void func(void *arg){

  my_type *x = (my_type *)arg;
  printf("%d %fn", *x->i1, *x->f1);

}

void do_stuff(void){

  func(my_ptr);

}


int main(void){

  init();
  do_stuff();


}

annigh

0 / 0 / 0

Регистрация: 07.05.2012

Сообщений: 8

1

Ошибка при передаче указателя функции

07.05.2012, 17:31. Показов 1336. Ответов 6

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Привет!
В моем понимании приведенный ниже код должен дважды выводить одно и то же. Объясните мне, почему это не так.

Код:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
 
void func(int *a, int *s);
 
int main(int argc, char *argv[]){
 
    int *array;
    int size, i;
 
    func(array, &size);
 
    for (i=0; i<size; i++)
        printf("%in", array[i]);
 
}
 
void func(int *a, int *s) {
    int j=0;
 
    *s = 5;
 
    a = (int *) malloc(sizeof(int) * *s);
    for(j=0; j < *s; j++)
        a[j] = j+5;
 
    for (j=0; j < *s; j++)
        printf("%in", a[j]);
 
}

Собственно, результат работы:

Код

5
6
7
8
9
1412476
-1216677816
4922752
1382974
1382990



0



26 / 26 / 7

Регистрация: 05.04.2012

Сообщений: 248

07.05.2012, 17:38

2

У вас указатель array не инициализирован, поэтому у меня, например, вообще не компилируется.



0



0 / 0 / 0

Регистрация: 07.05.2012

Сообщений: 8

07.05.2012, 18:05

 [ТС]

3

Хм, gcc не ругается.

Хорошо. Как его надо инициализировать, чтоб работало, как я хочу? То есть, чтоб функция писала в массив array.



0



Nameless One

Эксперт С++

5827 / 3478 / 358

Регистрация: 08.02.2010

Сообщений: 7,448

07.05.2012, 19:27

4

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

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
 
void func(int **array, size_t *size);
 
int main(void)
{
    int *array, i;
    size_t size;
    
    func(&array, &size);
    
    for(i = 0; i < size; ++i)
        printf("%dn", array[i]);
    
    exit(0);
}
 
void func(int **array, size_t *size)
{
    int j;
    
    *size = 5;
 
    *array = malloc(*size * sizeof **array);
    
    for(j = 0; j < *size; ++j)
        (*array)[j] = j + 5;
    
    for(j = 0; j < *size; ++j)
        printf("%dn", (*array)[j]);
}

У вас указатель array не инициализирован, поэтому у меня, например, вообще не компилируется.

Внутри функции func копия указателя инициализируется при вызове malloc. Но это изменение не затрагивает оригинальный указатель, объявленный в функции main. Компилятор на это максимум может предупреждение выдать



1



26 / 26 / 7

Регистрация: 05.04.2012

Сообщений: 248

07.05.2012, 21:01

5

Nameless One, я вас что, обманывать буду??….я ,правда, немного неправильно выразился, она как бы компилируется, но на этапе исполнения вылетает вот такая вот ошибка:
Run-Time Check Failure #3 — The variable ‘array’ is being used without being initialized.

Несложно перевести: переменная array была использована без инициализации.



0



0 / 0 / 0

Регистрация: 07.05.2012

Сообщений: 8

08.05.2012, 01:29

 [ТС]

6

Nameless One, спасибо, понял, заработало.



0



Эксперт С++

5827 / 3478 / 358

Регистрация: 08.02.2010

Сообщений: 7,448

08.05.2012, 04:49

7

Цитата
Сообщение от main.c
Посмотреть сообщение

поэтому у меня, например, вообще не компилируется.

Цитата
Сообщение от main.c
Посмотреть сообщение

я ,правда, немного неправильно выразился, она как бы компилируется, но на этапе исполнения вылетает вот такая вот ошибка:

Нифига себе «немного неправильно» . Ошибки компиляции и ошибки времени выполнения — это совсем разные вещи



0



Like this post? Please share to your friends:
  • Если фсс перечислил пособие а потом выяснилась ошибка
  • Если фсс обнаружат ошибку в больничном
  • Если фсс выявили ошибки в
  • Если стиральная машина гудит и выдает ошибку
  • Если стиральная машина выдает ошибку н20