简单问题?

Nsea 2003-11-27 02:47:56
char *stri = "usually";
strncpy(stri,"123",3);

以上代码有什么错误?
...全文
40 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
topwork 2003-11-28
  • 打赏
  • 举报
回复

char *stri = "abddddd";
strncpy(stri,"123",3);


我要指出的是这样做不是不可以,而是非常危险的,首先我们先看看这种语句会产生什么运行效果:
看看对应的汇编
mov dword ptr [ebp-4],offset string "abddddd" (0041fe50)
什么意思呢?就是在程序栈中申请四个字节的指针空间(ebp-4),然后(注意这是最关键的),把数据段里面的字符串首地址付给该指针。于是问题出现了,由于我们程序的数据段是写保护的,那么象我最上面举的例子就肯定不能运行成功了,因为它试图向写保护的内存段拷贝内容。就鉴于此我们才有了const关键字(当然const关键字不止干这一件事情),我们的变量可以这样定义:
const char *p = "string";
这样定义变量说明p指针指向的内容不可以修改,即如果程序这样写:
const char *stri = "usually";
strncpy(stri,"123",3);
那么编译的时候就会出错。
下面我再写一个例子,使各位大哥对我上面的叙述有更深入的了解:

#include "stdio.h"
int main(int argc, char* argv[])
{
DWORD dw;
char *p1 = "abddddd";
VirtualProtect(p1 , 8 , PAGE_READWRITE , &dw);
strncpy(p1 , "ABC" , 3);
VirtualProtect(p1 , 8 , dw , &dw);
printf(p1);
return 0;
}
大家看看这段程序会有什么运行结果?答案是运行不会出错,而且最后会打印"ABCdddd"这个结果,这说明我们也可以通过修改数据段的只读属性来达到修改自己的数据段内容的目的,但是我决不推荐这种用法,太危险了。
下面我们来看看几种正确的用法,这些用法所得到的字符串指针都可以随意操作的(不过可别越了界):

正确用法一:
char stri[] = "usually";
这段语句如何运行呢?见下:
mov eax,[string "usually" (0041f01c)]
mov dword ptr [ebp-8],eax
mov ecx,dword ptr [string "usually"+4 (0041f020)]
mov dword ptr [ebp-4],ecx
我们可以看到,程序首先把字符串"usually"的前四个BYTE,放到ebp-8位置,然后把后四个BYTE放到ebp-4位置,说句通俗的话就是程序在栈里面申请了一个8个字节长的缓冲区,然后把数据段中的内容分批复制到该缓冲区内,可能我们用的字符串刚好7个不太说明问题,下面我们看一个字符串稍长的例子:
char stri[] = "usuallyaabbcc";
对应代码:
mov eax,[string "usuallyaabbcc" (0041fe58)]
mov dword ptr [ebp-10h],eax
mov ecx,dword ptr [string "usuallyaabbcc"+4 (0041fe5c)]
mov dword ptr [ebp-0Ch],ecx
mov edx,dword ptr [string "usuallyaabbcc"+8 (0041fe60)]
mov dword ptr [ebp-8],edx
mov ax,[string "usuallyaabbcc"+0Ch (0041fe64)]
mov word ptr [ebp-4],ax
这段代码不用我解释了吧,总体说就是程序申请了一个16字节的缓冲区,然后把数据段的数据分四次复制过来,顺便说一句为什么申请16而不是14呢,因为我们现在用的32位系统对DWORD的操作最快(^_^,这是编译器的优化呀)。

正确用法二:
char stri[20] = "usuallyaabbcc";
看看代码:
mov eax,[string "usuallyaabbcc" (0041fe58)]
mov dword ptr [ebp-14h],eax
mov ecx,dword ptr [string "usuallyaabbcc"+4 (0041fe5c)]
mov dword ptr [ebp-10h],ecx
mov edx,dword ptr [string "usuallyaabbcc"+8 (0041fe60)]
mov dword ptr [ebp-0Ch],edx
mov ax,[string "usuallyaabbcc"+0Ch (0041fe64)]
mov word ptr [ebp-8],ax
这段代码与上面所述的第二个例子相似,所不同的是我们指定了缓冲区的大小(大小为20,0x14),其它地方一样的,这里不再叙述了。

正确用法三:
char *stri = new char[20];
strcpy(stri , "usuallyaabbcc");
这个例子我不贴汇编代码了,因为很好理解,就是首先在堆中申请空间,然后进行字符串复制。(不要忘记删除呀^_^)

我们前面叙述了多种字符串指针的申请方法都可以,但就是不能这样写:
char *p = "string";
如果非要这样写的话,也一定要写成这样:
const char *p = "string";
虽然第一种写法不会报错,而且还可以进行读操作,但是作为一名严谨的程序员,这种代码是不能出现的,即使知道自己在干什么也不可以,反正作为我个人的编码规则,程序中决不容许这种代码存在。
zhucde 2003-11-27
  • 打赏
  • 举报
回复
在C++里是可以这样写的,它的意义应该是:
char *stri;//定义一个字符指针,
然后将其中指向字符串"usually"的首地址
topwork 2003-11-27
  • 打赏
  • 举报
回复
char *stri="usually";
这是什么用法?我已经看到好几个这样写的了,没有任何意义,从C语法上讲,指针必须指向变量的首地址,不能指向常量。
Nsea 2003-11-27
  • 打赏
  • 举报
回复
我一执行就说内存不能写呢
zhucde 2003-11-27
  • 打赏
  • 举报
回复
非法退出?

我的电脑上用我的程序:
char *stri = "usually";
strncpy(stri,"123",3);
MessageBox(stri);

一点错误也没有,最后显示出的stri是"123ally"
carbon107 2003-11-27
  • 打赏
  • 举报
回复

char *stri = new char(20);
char kk[20]= "usually";
stri = kk;
strncpy(stri,"123",3);
carbon107 2003-11-27
  • 打赏
  • 举报
回复
char *stri = "usually";
stri要是指针,要申请空间,用new
改为
char stri[20] = "usually";

Nsea 2003-11-27
  • 打赏
  • 举报
回复
但是程序执行就非法退出!
public 2003-11-27
  • 打赏
  • 举报
回复
指针stri指向字符串常量了。
应该改为


char stri[] = "usually";
strncpy(stri,"123",3);

zhucde 2003-11-27
  • 打赏
  • 举报
回复
没有错啊!
strncpy用来拷贝字符串,
strncpy(stri,"123",3);
将"123"拷贝到stri,替换了前面三个,
执行后,stri变成123ally,
可能没有达到你的目的,但程序是没错的

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧