我准备了一个示例程序,它将char数组的第二个元素移动到第一个位置,第三个元素移动到第二个位置等。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
int main(void) {
char *str = (char *) malloc(10);
strcpy(str, "123456");
printf("%s\n", str); //123456
str++;
printf("%s\n", str); //23456
str++;
printf("%s\n", str); //3456
str++;
printf("%s\n", str); //456
std::cout << str[0]; //4
}
现在我想重复这个操作但是使用移位操作,但它并没有像我期望的那样真正起作用。
#include<iostream>
int main(void){
char tab[6] = {'1','2', '3', '4', '5', '6'};
char *p = tab;
for(int i = 0; i < 6; i++){
std::cout << tab[i]; //123456
}
std::cout << std::endl;
*p = *p << 8;
std::cout << tab[0] << std::endl; //0 '\0'
std::cout << tab[1] << std::endl; //2
std::cout << std::endl;
return 0;
}
如果数组名是第一个元素的指针,我希望数组名的左移操作指向数组的第二个元素,但它不会。有关如何使用移位操作重复第一个指针操作的想法吗?
答案 0 :(得分:1)
如果数组名是第一个元素的指针,我希望左移 对数组名称的操作将指向数组的第二个元素
表达式中的数组指示符是隐式的(极少数例外)确实转换为指向其第一个元素的指针
因此在此声明中
char *p = tab;
数组指示符tab
被转换为指向其第一个元素的指针,第一个元素的地址被指定给指针p
。
但是在这个表达式声明中
*p = *p << 8;
指针*p
指向的第一个字符p
的值实际上乘以功率8中等于2的值乘以256.并且字符的值被分配给指针。
因此,在此操作之后,指针具有无效值,因此程序具有未定义的行为。
您需要的是将从索引1开始的数组的所有元素复制到与索引0对应的位置。
同样在第一个程序中,您使用的是字符串,但在第二个程序中,该数组不包含字符串。
如果要移动包含字符串的字符数组的左侧元素,则代码可以看起来像在演示程序中显示的函数中实现。
#include <iostream>
#include <cstring>
char * shift_left(char *s)
{
size_t n = std::strlen(s);
std::memmove(s, s + 1, n);
return s;
}
int main()
{
char s[] = "123456";
std::cout << s << std::endl;
for (size_t i = 0, n = std::strlen(s); i != n; i++ )
{
std::cout << shift_left( s ) << std::endl;
}
return 0;
}
程序输出
123456
23456
3456
456
56
6
答案 1 :(得分:0)
此@Provides
不会移动指针,它会移动指针指向的对象中的值。 (char被隐式转换为int,右移8位,并隐式转换回char。然后该值(在具有8位char的平台上为0)将被放回{{1 }}。)
因为它指向一个char,而char(可能)是8位,我认为*做一个*p = *p << 8;
是UB。
* 98.3%肯定。
答案 2 :(得分:0)
如果数组名是第一个元素的指针,我希望数组名的左移操作指向数组的第二个元素,但它不会。
这种期望是没有根据的。位移操作对整数类型有效,而不是指针类型。
来自https://timsong-cpp.github.io/cppwp/n3337/expr.shift#1:
操作数应为整数或无范围的枚举类型,并执行整体促销。
有关如何使用移位操作重复第一个指针操作的任何想法吗?
你不应该试图这样做。我很肯定这是未定义的行为。
最好使用指针或数组元素的索引来迭代数组。
答案 3 :(得分:0)
问题在于位移和指针运算之间没有关系。
首先,让我们看看为什么第一个代码有效,第二个代码没有:
想象一下,我有一个名为'p'的指针,其值为4,指向数组的第一个位置{e,x,a,m,p,l,e}。这意味着您打印p和* p的值,您将分别得到“4”和“e”。发生这种情况是因为'e'是指针指向的值,'4'是指针指向的内存地址。如果向指针的值添加+1,则将指向此数组的第二个位置。因此,如果您再次打印p和* p的值,则分别得到“5”和“x”。
当您编写命令行*p = *p << 8
时,您实际上正在将您指向的值向左移动8位。这意味着如果 p 指向第一个位置,则“e”(ASCII值等于十进制的101或十六进制的基数为0x65)将被移位8位并变为0x0,是一个空字符。但是,指针的值将保持不变。如果打印p和* p值,则分别得到“4”和 null 值。
另一方面,如果您编写p = p << 8
,您将更改指针值(以及它指向的内容)。如果p的值为“4”,它将成为a
转移后“1024”。
使用指针算法比使用位移更容易实现所需的功能。
答案 4 :(得分:0)
关于:
*p = *p << 8;
这是取数组的第一个字节(最初包含0x31)
并将字节移位8位(因此它现在包含0x00)
然后将结果存储回数组的第一个字节。
这不会改变整个阵列。