2

我有下面的代码,通过填充0作为前缀将 IP 地址固定为 15 位。

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h> 

char *function(char *newhost){
     char *IPaddr;
     IPaddr = (char *)calloc(16, sizeof(char));

    size_t i=0 , j= 0;
    for(i=0, j=0; j<15; i++, j++){
        if((newhost[strlen(newhost)-(i+1)] == '.')){   //////////line 11
            if( j == 3 || j == 7 || j == 11){
                IPaddr[14-j] = '.';
            }else if(j<3){
                while(!(j==3)){
                    IPaddr[14-j]='0';
                    j++;
                }
                IPaddr[14-j] = '.';
            }else if(j > 3 && j<7){
                while(!(j==7)){
                    IPaddr[14-j]='0';
                    j++;
                }
                IPaddr[14-j] = '.';
            }else if(j>7 && j<11){
                while(!(j==11)){
                    IPaddr[14-j]='0';
                    j++;
                }
                IPaddr[14-j] = '.';
            }
        }else if(newhost[strlen(newhost)-(i+1)] == '\0'){ ///////////line33
            while(!(j==15)){
                IPaddr[14-j] = '0';
                j++;
               }
        }else{
            IPaddr[14-j] = newhost[strlen(newhost)-(i+1)];
        }
    }
    printf("IPaddr: %s\n", IPaddr);
    return IPaddr;

}


int main(int argc,char *argv[]){  /////////line48
    char host[100] = {'\0'};
    strcpy(host, "10.0.0.2");
    char *new_IP;
    new_IP = function(host);  ////////////line52
    printf("newIP:%s\n",new_IP);
    free(new_IP);

return 0;
}

该代码有效,编译器既不输出错误也不输出警告。但是,valgrind 输出(valgrind --tool=memcheck --leak-check=yes --track-origins=yes test )

==22544== Conditional jump or move depends on uninitialised value(s)
==22544==    at 0x8048547: function (test.c:11)
==22544==    by 0x804872B: main (test.c:52)
==22544==  Uninitialised value was created by a stack allocation
==22544==    at 0x80486DB: main (test.c:48)
==22544== 
==22544== Conditional jump or move depends on uninitialised value(s)
==22544==    at 0x8048654: function (test.c:33)
==22544==    by 0x804872B: main (test.c:52)
==22544==  Uninitialised value was created by a stack allocation
==22544==    at 0x80486DB: main (test.c:48)

谁能告诉我如何修复代码?

4

1 回答 1

5

问题是在函数中,你正在做:

for (i=0, j=0; j < 15; i++, j++){
    if ((newhost[strlen(newhost)-(i+1)] == '.')){  

当您通过循环时,它i变得大于初始化字符串的长度,但我希望这会产生“越界”错误。但是,由于变量 inmain()不是动态分配的,因此可能valgrind无济于事。我建议修改main()为:

int main(int argc, char *argv[])
{
    char *host = malloc(100);
    if (host != 0)
    {
        strcpy(host, "10.0.0.2");
        char *new_IP = function(host);
        printf("newIP:%s\n", new_IP);
        free(host);
        free(new_IP);
    }
    return 0;
}

我希望valgrind抱怨更多的问题,特别是越界内存访问。

分别地:

  • 由于strlen(newhost)在函数运行时不会更改,因此您应该在循环之外计算一次。
  • 我不确定你为什么使用这个if ((...))符号。如果它是一种反射动作来避免编译器警告在条件中使用赋值,那么你就违背了警告的目的。
  • sscanf()将字符串解析为 4 个数字,然后使用 格式化它们会更容易sprintf()吗?

    char *function(const char *newhost)
    {
        int o1, o2, o3, o4;
        char *result = 0;
        if (sscanf(newhost, "%d.%d.%d.%d", &o1, &o2, &o3, &o4) == 4)
        {
            /* Should check that values are in range 0..255 */
            result = malloc(16);
            if (result != 0)
                sprintf(result, "%.3d.%.3d.%.3d.%.3d", o1, o2, o3, o4);
        }
        return result;
    }
    

您的另一个替代实现,function()仅使用字符串复制:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *function(const char *newhost)
{
    char *result = malloc(16);
    if (result != 0)
    {
        strcpy(result, "000.000.000.000");
        const char *beg = newhost;

        for (int i = 0; i < 4; i++)
        {
            const char *end = strchr(beg, '.');
            if (end == 0)
                end = beg + strlen(beg);
            memcpy(result + (i * 4) + 3 - (end - beg), beg, end - beg);
            beg = end + 1;
        }
    }
    return result;
}

int main(void)
{
    char host[] = "10.0.0.2";
    char *newhost = function(host);
    printf("%s => %s\n", host, newhost);
    free(newhost);
    return 0;
}

这会计算每个段中有多少位,然后将其复制到结果缓冲区中的正确位置,该缓冲区已经在正确的位置填充了零和点。它避免了像 3、7、11 这样乱扔原始代码的幻数。

我还建议使用不同的接口来运行,避免动态内存分配:

void function(const char *oldhost, char *newhost)

我们可以讨论voidvs int,但调用函数应该提供(已知的,固定大小的)缓冲区,输出将被写入其中,以避免必须进行动态内存分配。int如果函数对给定的字符串进行任何验证,您将使用它;否则,它可以是void。如果传递了错误的 IP 地址,现有代码大多不会报告错误。

于 2013-07-14T16:04:18.570 回答