Загрузка…
Токен &
В С++ этот токен имеет много значений:
-
Как бинарный оператор — оператор побитового «и».
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 Метки нет (Все метки)
Привет! Код:
Собственно, результат работы: Код 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, то нужно передавать не сам указатель, а его адрес
У вас указатель array не инициализирован, поэтому у меня, например, вообще не компилируется. Внутри функции func копия указателя инициализируется при вызове malloc. Но это изменение не затрагивает оригинальный указатель, объявленный в функции main. Компилятор на это максимум может предупреждение выдать
1 |
26 / 26 / 7 Регистрация: 05.04.2012 Сообщений: 248 |
|
07.05.2012, 21:01 |
5 |
Nameless One, я вас что, обманывать буду??….я ,правда, немного неправильно выразился, она как бы компилируется, но на этапе исполнения вылетает вот такая вот ошибка: Несложно перевести: переменная 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 |
поэтому у меня, например, вообще не компилируется.
я ,правда, немного неправильно выразился, она как бы компилируется, но на этапе исполнения вылетает вот такая вот ошибка: Нифига себе «немного неправильно» . Ошибки компиляции и ошибки времени выполнения — это совсем разные вещи
0 |