【问题标题】:Doing a direct struct read in C from preallocated memory failed在 C 中从预分配的内存中直接读取结构失败
【发布时间】:2015-02-11 04:54:32
【问题描述】:

我再次假设它是一个指针问题,但我在这里要做的是有一个函数搜索内存来查看是否存在 IP 地址,如果不存在,则保留一个随机内存空间用于IP 地址并返回零。该函数将 IP 地址作为字符串作为第一个参数,第二个参数指向结构。当 main() 函数执行时,result 应该等于 0,result2 应该等于 1,但是,我得到了崩溃,我认为这与我分配指针的方式有关?

在这个片段中...

ip=(iprec*)p;

我正在尝试设置传递给函数的 iprec 结构(之前由 malloc 分配),但我不确定在该语句中添加或删除星号的位置。

这是其余的代码。

char *shma;

typedef struct{
    unsigned char u;
    unsigned char a[4];
    unsigned int otherdata;
} iprec;

static int loadip(char* remoteip,iprec *ip){
    char *p=shma;
    int v=0;
    char *ep;
    unsigned char a[4];
    sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
    int i,n;int sz=5000;
    int szr=sizeof(iprec);
    for (i=3;i<sz;i+=szr){
        ip=(iprec*)p;
        if (ip->u=='Y'){
            for (n=0;n<=4;n++){
                if (a[n]!=ip->a[n]){break;}
            }
            if (n >= 3){v=1;break;}
        }else{
            ep=p;
        }
        p+=szr;
    }
    if (v==0){
        ip=(iprec*)ep;
        for (n=0;n<=3;n++){
            ip->a[n]=a[n];
        }
    }
    return v;
}

int main(){
    char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
    iprec *x=(iprec*)malloc(sizeof(iprec));
    int result=loadip("127.0.0.1",x);
    int result2=loadip("127.0.0.1",x);
}

【问题讨论】:

  • 0) char *shma=(char*)malloc(5000); 设置为局部变量 shma
  • 1) ip=(iprec*)p; ip 的未使用参数
  • 2) sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]); : a[0],a[1],a[2],a[3] 不是int *,只是char

标签: c struct


【解决方案1】:
  1. 替换

    sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);

sscanf(remoteip,"%d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3]);

sccanf 需要指针类型参数。

  1. shma 应该是全局的。

【讨论】:

  • 我尝试字符类型参数的原因是因为我想将 IP 存储为四个字符,以便内存要求是 4 个字节而不是 8 个或 16 个字节。
  • 我在回答中错过了 sscanf,但我想在此处补充一点,您应该使用 %d 而不是 %hhd 以确保分配给字符宽度数据。仅使用 %d 会使用自然 int 大小,这可能会导致数据不正确,具体取决于主机的字节序,并可能导致覆盖任何机器上的相邻数据(有时还会导致对齐错误)。
【解决方案2】:

我尚未对您的代码进行全面分析,但这里是您崩溃的根源。底部是分辨率

分析

在你的 sn-p 的顶部,你有

char *shma;

这是一个名为 shma 的文件范围(全局)对象,具有静态持续时间存储。它在 main() 执行之前被初始化为 0。

然后,主要是:

int main(){
    char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.

在这里,您声明了一个名为 shma 的新对象。它具有块范围(仅存在于 main 的上下文中),具有自动存储功能。你为它分配了一个来自 malloc() 的指针。然后你打电话给loadip

loadip

char *p=shma;

它声明了一个名为 p 的新对象,具有块范围(存在于 loadip 中)并具有自动存储功能。您将其设置为shma注意这是分配全局 shma,而不是 main 中的那个,因为 main 中的那个只存在于 main 中,而 loadip 位于 main 之外。全局 shma 为 0,所以现在 p 也是 0(至少对于您的第一个循环)。

然后,你这样做:

    ip=(iprec*)p;

所以,由于 p 为 0,现在 ip 为 0。在下一行:

    if (ip->u=='Y'){

您正在取消引用 ip 以获取成员 u。在大多数系统上,此取消引用将导致分段错误(或类似的内存访问冲突),因为您实际上已取消引用 NULL(0 地址)。

修复此问题

改变

int main(){
    char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.

进入

int main(){
    shma=(char*)malloc(5000); //alloc 5000 bytes for example.

这将导致主分配给全局shma,而不是创建一个新的本地。

【讨论】:

  • 我本来打算那样做的。我在赶主要功能。
【解决方案3】:

我学习 C 已经有一段时间了,但有一些想法:

char *p=shma;

但 shma 尚未初始化 - 因此 "ip=(iprec*)p;"表示 ip 将不是有效值。

unsigned char a[4];
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);

您需要接收变量的地址(即&a[0]、&a[1]、...)。 另外,由于 '%d' 将写入 4 字节整数(scanf 不知道它是一个 char 数组),所以最好有 "int a[4]"

ip=(iprec*)p;

但是 ip 是一个输入参数 - 所以在这里你将覆盖(即丢弃)用户在第二个参数中提供的任何值。

if (v==0){
    ip=(iprec*)ep;

即使 v=0,仍然有可能 ep 尚未初始化(例如,如果所有 ip->u == 'Y' 但 a-arrays 在第一个或第二个值上不同)

【讨论】:

  • 这似乎可行,但我的功能很慢。 static int loadip(request_rec *r,iprec *cip){ int v=0;char*p=shma;iprec *ep; unsigned int a[4];sscanf(r-&gt;connection-&gt;remote_ip,"%d.%d.%d.%d",&amp;a[0],&amp;a[1],&amp;a[2],&amp;a[3]); dir_config *dir=loadscfg(r-&gt;server); int i,n;int sz=dir-&gt;PSZ,szs=sizeof(iprec); for (i=1;i&lt;sz;i+=szs){ iprec *cip=(iprec*)p; if (cip-&gt;u=='Y'){ for (n=0;n&lt;=4;n++){if (a[n]!=(unsigned char)cip-&gt;a[n]){break;}} if (n &gt;= 3){v=1;break;} }else{ ep=(iprec*)p; } p+=szs; } if (v==0){ep-&gt;u='Y';for (n=0;n&lt;=3;n++){ep-&gt;a[n]=a[n];}} return v; }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-29
  • 1970-01-01
  • 2014-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多