有三种结构; 阵列a和b与指针c:
c --------------------------.
|
V
___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
a --> | a | \0| \0| \0| \0| b | i | g | \0| \0| r | i | d | e | \0|
´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´ ´´´
___ ___ ___ ___ ___ ___ ___
b --> | F | …Run Code Online (Sandbox Code Playgroud) 今天我浏览了一些源代码(这是一个解释软件框架使用的示例文件)并发现了很多这样的代码:
int* array = new int[10]; // or malloc, who cares. Please, no language wars. This is applicable to both languages
for ( int* ptr = &(array[0]); ptr <= &(array[9]); ptr++ )
{
...
}
Run Code Online (Sandbox Code Playgroud)
所以基本上,他们已经完成了"获取位于地址的对象的地址array + x".
通常我会说,这是明显的愚蠢,因为写作array + 0或array + 9直接做同样的事情.我甚至总是会将这样的代码重写为size_t for循环,但这是一个风格问题.
但过度使用这个让我思考:我是否遗漏了一些明显的东西或者隐藏在语言黑暗角落里的东西?
对于任何想要查看原始源代码的人来说,有了它所有令人讨厌的gotos,mallocs当然还有这个指针的东西,请随时在线查看.
我经常看到使用普通指针算法的数组迭代,即使在较新的C++代码中也是如此.我不知道它们到底有多安全,如果使用它们是个好主意.考虑这个片段(如果你calloc代替它,它也在C中编译new):
int8_t *buffer = new int8_t[16];
for (int8_t *p = buffer; p < buffer + 16; p++) {
...
}
Run Code Online (Sandbox Code Playgroud)
这种迭代不会导致溢出,并且当buffer 碰巧在地址0xFFFFFFF0(在32位地址空间中)或0xFFFFFFFFFFFFFFF0(64位)分配时,循环会被完全跳过吗?据我所知,这将是一个异常不幸,但仍然可能的情况.
专用于内置阵列的范围原语消耗它们的源,但是可以很容易地设计一个范围系统,而不是基于.ptr源的范围系统(首先看起来更灵活).
struct ArrayRange(T)
{
private T* _front;
private T* _back;
this(ref T[] stuff) {
_front = stuff.ptr;
_back = _front + stuff.length;
}
@property bool empty(){return _front == _back;}
@property T front(){ return *_front;}
@property T back(){return *_back;}
void popFront(){ ++_front;}
void popBack(){--_back;}
T[] array(){return _front[0 .. _back - _front];}
typeof(this) save() {
auto r = this.array.dup;
return typeof(this)(r);
}
}
void main(string[] args)
{
auto s = "bla".dup;
// here the source is 'fire-proofed'
auto rng = …Run Code Online (Sandbox Code Playgroud) 我需要在C++中实现矩阵转置过程.问题是签名,函数必须像这样调用:
transpose(in_mat[0][0], n, m, out_mat[0][0])
Run Code Online (Sandbox Code Playgroud)
其中n和m是尺寸.所有值都是双精度,包括矩阵和维数.
由于代码是自动生成的,我无法解决这个问题.
我的解决方法如下所示:
void transpose(double& in_mat, const double _n, const double _m, double& out_mat)
{
int n = _n, m = _m;
double* in_pointer= &in_mat;
double* out_pointer= &out_mat;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
*(out_pointer+(j*n+i)) = *(in_pointer+(i*m + j));
}
}
}
Run Code Online (Sandbox Code Playgroud)
它工作正常.我构建了一个测试用例,其中包含两个不同宽度和高度的矩阵.一个用随机数填充,另一个用零填充.然后调用转置过程并比较两个矩阵.功能是正确的.
但它破坏了堆栈.在Visual Studio 2015中运行时会出现警告
运行时检查失败#2 - 变量'in_mat'周围的堆栈已损坏.
我做错了什么 ?为什么堆栈已损坏?转置调用后的代码正常工作.
编辑:
这是完整的设置:
#include <random>
#include <iostream>
void transpose(double& in_mat, const …Run Code Online (Sandbox Code Playgroud) 在符合AMD64标准的体系结构中,地址需要在取消引用之前采用规范形式.
在64位模式中,如果微架构的地址位63到最重要的实现位被设置为全1或全零,则认为地址是规范形式.
现在,当前操作系统和体系结构中最有意义的实现位是第47位.这给我们留下了48位的地址空间.
特别是当启用ASLR时,用户程序可能会收到第47位设置的地址.
如果使用指针标记等优化并且高位用于存储信息,则程序必须确保将第48位至第63位设置回取消引用地址之前的第47位.
但请考虑以下代码:
int main()
{
int* intArray = new int[100];
int* it = intArray;
// Fill the array with any value.
for (int i = 0; i < 100; i++)
{
*it = 20;
it++;
}
delete [] intArray;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在考虑的intArray是,说:
0000 0000 0000 0000 0 111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1100
设置it到intArray并增加it一次,并考虑sizeof(int) == …
char array[8] = "Raining";
Run Code Online (Sandbox Code Playgroud)
我认为以下所有相关陈述的评论都符合我的理解.
char *p1 = array + 7; --> points to '\0'
char *p2 = array + 8; --> undefined behaviour
char *p3 = array + 9; --> undefined behaviour
char *p4 = array + 10; --> undefined behaviour
Run Code Online (Sandbox Code Playgroud)
我的理解是否正确?
我正在编写一个程序,我必须修改目标进程内存/读取它.
到目前为止,我使用void*来存储地址并将其转换为char*如果我需要更改它们(添加偏移量或修改一般)
我听说过在stdint.h中定义的那个类型,但我没有看到使用它进行char*转换的指针算法的差异(这对我来说似乎更C89友好)
所以我的问题是:我应该将哪两种方法用于指针算法?在任何情况下我是否应该考虑使用uintptr_t而不是char*?
编辑1
基本上我只需知道这是否会产生
0x00F00BAA hard coded memory adress in target
process
void* x = (void*)0x00F00BAA;
char* y = (void*)0x00F00BAA;
x = (uintptr_t)x + 0x123;
y = (char*)y + 0x123;
x == y?
x == (void*)0x00F00CCD?
y == (void*)0x00F00CCD?
Run Code Online (Sandbox Code Playgroud) 尽管void ptr算术不是标准的,但以下代码是使用 gcc 编译的:
int main(){
int a = 5;
void* b = (void*) &a;
b++;
}
Run Code Online (Sandbox Code Playgroud) 考虑到 C++17 中引入的语义变化(例如在具有正确地址和类型的指针自 C++17 以来是否仍然始终是有效指针中进行了讨论) ,XOR 链接列表以一种对我来说看起来很可疑的方式使用指针算术。)。它们现在会导致未定义的行为吗?如果是这样,可以通过洗涤来拯救它们吗?
编辑:
维基百科文章仅包含有关指针和整数之间转换的简短注释。我默认(现在明确声明)指针首先被转换为足够大小的整数类型以适合它们,然后对整数进行异或。因此,操作理论中列出的 XOR 属性保证只有从指针获得一次的整数才会被转换回它们。根据标准,从指针到整数的实际映射可以是任意注入。除此之外我不依赖任何假设。
标准是否允许使用它们并访问仍然存在的对象?C++17 之前?从 C++17 开始?