类似 C 语言中的指针问题, 如何操作?

printer

类似于 C 语言里的指针问题: 如图, 一个变量存储着另一个变量的地址. 我如何去访问并修改 hello 这个值?

Emacs Lisp 学得不好, 不知道如何更好地描述这个问题, 请见谅.

a 指向 "hello"b 指向同一个"hello",所以修改 b 也就是修改 a

(let* ((a "hello")
       (b a))
  (aset b 0 ?H)
  a)
;; => "Hello"

a 指向 "hello"bcar 指向同一个`“hello”

(let* ((a "hello")
       (b (list a)))
  ;; 通过 b 修改 a
  (aset (car b) 0 ?H)
  a)
;; => "Hello"

看起来 Emacs Lisp 没有「指向指针的指针」。

(Emacs Lisp 字符串是可修改的,但是实际上一般把字符串当作常量而不修改它)

2 个赞

感谢耐心解答问题!

法一我的理解是, 变量 a 和变量 b 同时指向了同一个 hello. 换句话说, 这两个变量完全是一回事, 因为都指向了同一个内存地址. 这个貌似与题不相符.

法二我暂时理解不了, mark 一下日后看.

我刚学 setf 这个函数, 我的想法是:

(let ((str '("h" "e" "l" "l" "o"))
      (return-str ""))
  (setf (car str) "H")
  (dolist (el str)
    (setq return-str (concat return-str el)))
  return-str)
  
  ;; ===> "Hello"
1 个赞
ELISP> (setq a "hello")
"hello"
ELISP> (setq b 'a)
a
ELISP> (setf (symbol-value b) "world")
ELISP> a 
"world"

但就允许用户的操作来说,这里面并没有一个变量保存了另一个变量的地址

1 个赞

@Angelaneia @steiner 感谢!

Emacs Lisp 没法表示「指向一个指针的指针」,所以不会出现你图中的情形。

elisp 没有指针的概念,想操作指针,只能退回到 c 语言层面了,例如楼上几位提到的 aset/set(setf)。

如果一定要找出对应关系,也并非无迹可寻:

#+BEGIN_SRC emacs-lisp :results value
(let* ((a "hello")
       (b 'a))
  ;; (setf (symbol-value b) "world")
  ;; 等于
  ;; (set b "world")
  ;; 等于
  (set 'a "world")

  ;; (aset (symbol-value b) 0 ?W)
  ;; 等于
  (aset a 0 ?W)

  a)
#+END_SRC

#+RESULTS:
: World
#+BEGIN_SRC C :results output :includes <stdio.h> :flags -std=gnu99 -Wall -Werror
char a[10] = "hello\n";
char *p;

p = &a[0]              // 相当于 (let (... (b 'a)) ...)

sprintf(p, "world\n"); // 相当于 (set b "world")
*p = 'W';              // 相当于 (aset (symbol-value b) 0 ?W)
// a[0] = 'W';         // 相当于 (aset a 0 ?W)

printf("%s\n", a);
#+END_SRC

#+RESULTS:
: World

可以把 symbol 看作指针:

| 操作 | elisp                           | C           |
|------+---------------------------------+-------------|
| 寻址 | (symbol-value b)                | *p          |
| 取址 | 'a                              | &a          |
| 下标 | (aset a 0 ?W)                   | a[0] = 'W'  |
|      | 或 (aset (symbol-value b) 0 ?W) | 或 *p = 'W' |
2 个赞

十分感谢回复!

今天我碰到了指针的需求(想在函数里面改变传参的原变量的值),查了一下,发现有个不错的解决方案:

(gv-ref) 相当于 C 的 &(gv-deref) 相当于 C 的 *
于是可以有以下操作:

(setq test 'test)

(defun test1 (a)
  (setf (gv-deref a) nil))

(test1 (gv-ref test))
test
;; ===> nil
4 个赞