【问题标题】:I can't return a character string in C我无法在 C 中返回字符串
【发布时间】:2021-09-03 11:53:34
【问题描述】:

你好;

我的程序有问题,需要计算 IP 地址的@host 网络。该程序的步骤是:

  1. 将掩码和 ip 添加到二进制(int 格式)的“网络”变量中
  2. 将“reseau”变量转换为十进制(在 char[] 中)
  3. 在 main 中返回“network”变量

无论如何,我在第 1 步。为了看到一切正常,我试图返回包含二进制加法的字符串“reseau”。

问题:很遗憾,我做不到。它给了我以下错误代码:

从返回类型为 'char' 的函数返回 'char *' 使得 没有强制转换的整数 [-Wint-conversion] 33. return reseau;

我怀疑这是因为您无法返回这样的字符标签(根据我的研究),但我无法弄清楚。

代码:

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

char calcul(char* octet, char* masque);

void main(){
    char octetB[]="11000000101010000000000100000111";
    char masqueB[]="11111111111111111111111100000000";

    printf("octetB : %s\n", octetB);
    printf("octetB 3e valeur : %c\n", octetB[2]);

    printf("Adresse réseau : %s\n", calcul(octetB, masqueB));
}

char calcul(char* octet, char* masque){
    int i;
    char reseau[100];

    printf("\n");
    printf("octet dans calcul : %s\n", octet);
    printf("masque dans calcul : %s\n", masque);

    for(i=0; i<32; i++){
        if((octet[i]='1') && (masque[i]='1')){
            reseau[i]='1';
        } else {
            reseau[i]='0';
        }
        printf("nombre %d : %d\n", i, reseau[i]);
    }
    return reseau;
}

所以我很想得到一些帮助来知道我哪里出错了? 为了理解。谢谢:D

【问题讨论】:

  • 你不能返回reseau,那个变量是本地的,我敢肯定有很多重复解决这个问题。
  • 另外,为了解决这个错误,如果你有一个可以返回的有效字符串,你的返回类型必须是char* calcul...
  • @Baptiste B - 当然你可以返回(并因此使用)一个 local 变量的(地址);范围没有障碍,生命周期是。声明static char reseau[100];。 - 除了anastaciu 建议的更改之外,您进行了不合理的更改。
  • @Armali 如果函数不使用全局/静态数据,那么您不必将其记录为线程不安全,如果被 OP/其他人或设计更改,因此不会成为另一个 strtok()。这可能不是问题,但应该记录带有约束的代码(尤其是在 SO 上),或者删除约束。

标签: c function char


【解决方案1】:

问题是您的函数calcul() 返回一个字符数组或一个指向字符的指针 (char*),尽管您的函数定义说返回类型是 char。这就是您收到编译错误的原因。

但是你不能返回数组reseau。此变量是本地变量,仅在您的函数中可用。在函数 calcul() 之外,此字符数组不再有效。

您的代码中的下一个问题是 reseau 最后没有 nul 终止。所以你的printf() 不会像你预期的那样工作。

最后我在你的代码中发现了另一个问题。语句octet[i]='1' 是一个赋值。在您的情况下,您需要进行比较。您必须将其更改为 octet[i]=='1'(带有双等号)。

【讨论】:

  • 同上masque[i] = '1'
  • 这是对相关代码中问题的全面总结。但是,您没有为返回字符串的主要问题提供解决方案。
  • @Clifford:我只是想给出代码中问题所在的一些提示。所以写这个问题的人有机会找到自己的解决方案,而不是仅仅给他们一个完整的代码sn-p。
  • 我明白了。然而,SO 是一个问答和资源,供其他人寻求类似问题的答案。在这种情况下,至少有三种可能的解决方案,其中只有一种是合适的,而这里的 OP 已导致其中最不合适的一种。不是特别通过这个答案,而是本着帮助新手改进的精神,一个带有解释/理由的答案 - 而不仅仅是“复制这个代码”的答案可能是合适的。
【解决方案2】:

向上:

我已经考虑了您的 cmets 和解释。现在它可以工作了(使用 malloc 系统)。

感谢您的 cmets。

这里是更新的代码,供那些会遇到该主题的人使用:

char* calcul(char* octet, char* masque){
    int i;
    char reseau[100];

    printf("\n");
    printf("octet dans calcul : %s\n", octet);
    printf("masque dans calcul : %s\n", masque);

    for(i=0; i<32; i++){
        if((octet[i]=='1') && (masque[i]=='1')){
            reseau[i]='1';
        } else {
            reseau[i]='0';
        }
        printf("nombre %d : %d\n", i, reseau[i]);
    }
    char* result = malloc(strlen(reseau)+1);
    strcpy(result, reseau);
    return result;
}

【讨论】:

  • 这是导致内存泄漏的秘诀 - 不要那样做。
  • reseau 数组、strlen()strcpy() 是不必要的 - 长度是固定的 (32+1),您可以分配那么多空间并直接写入。即使不是这样,如果i的值已经等于字符串长度,至少不需要调用strlen()
【解决方案3】:

您的代码无法编译,因为您在 calcul() 函数中返回了 char 并返回了一个字符数组。如果要返回 reseau 字符数组,可以使用指针来完成。看看下面的代码与你的代码的区别,看看如何实现它。

您的代码中还存在一些逻辑问题,例如reseau 数组中没有结束行,这导致在您想要的字符串之后打印垃圾值。并且您使用一个相等的= 而不是双相等的== 在您的代码中比较相等。

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

const char* calcul(char* octet, char* masque);

int main(){
    char octetB[]="11000000101010000000000100000111";
    char masqueB[]="11111111111111111111111100000000";

    printf("octetB : %s\n", octetB);
    printf("octetB 3e valeur : %c\n", octetB[2]);

    printf("Adresse réseau : %s\n", calcul(octetB, masqueB));
}

const char* calcul(char* octet, char* masque){
    int i;
    char *reseau = malloc(100);
    printf("\n");
    printf("octet dans calcul : %s\n", octet);
    printf("masque dans calcul : %s\n", masque);

    for(i=0; i<32; i++){
        if((octet[i]=='1') && (masque[i]=='1')){//use double equal to compare
            reseau[i]='1';
        } else {
            reseau[i]='0';
        }
        printf("nombre %d : %c\n", i, reseau[i]);
    }
    reseau[i]= '\0';//add endline
    return reseau;
}

【讨论】:

  • 我建议在这种情况下“隐藏”动态内存分配是一种不合适且危险的解决方案。
【解决方案4】:

使用malloc() 的解决方案的缺点是分配了内存,但释放该内存的责任不明确。调用者甚至不需要知道内存是动态分配的(为什么要这样做?),并且未能释放它导致内存泄漏。通常,释放分配的责任应该是明确的。在这种情况下,这不是一个好的解决方案。

一个简单(但仍然不完美)的解决方案是静态分配返回的字符串:

const char* calcul( const char* octet, const char* masque )
{
    static char reseau[33] = "" ;

    ...

    return reseau;
}

然而,这有一个问题是不可重入(多线程或递归代码中的一个问题),调用者仍然需要了解与使用静态缓冲区相关的限制和问题。返回的指针对于所有调用者都是相同的,因此如果随后调用该函数,该字符串将被修改。调用者可以复制字符串,或确保在再次调用函数之前已完成对其的所有处理。动态内存分配可能更好,但仍然需要调用者了解内部内存管理才能正确使用它。

该解决方案的另一个缺点是返回const 不能在函数外部执行写访问,因此如果有必要,调用者必须将字符串复制到本地缓冲区。返回一个非常量将是一个非常糟糕的主意 - 您将修改函数内的“隐藏”缓冲区。

更常用和更灵活的习惯用法是让调用者“拥有”缓冲区并将其传递给函数以进行填充。这样内存可以是一个数组,或者根据调用者的需要动态分配。在这种情况下,您还将传递数组的长度,以便函数可以避免超出调用者的缓冲区:

const char* calcul( const char* octet, const char* masque, 
                    char* reseau, size_t reseau_len )
{
    ...

    for( i = 0; 
         octet[i] != 0 && masque[i] != 0 && i < reseau_len; 
         i++)
    {
        ...
    }

    return reseau;
}

那么函数可能会这样调用:

    char reseau_buf[sizeof(octetB)] ;
    printf( "Adresse réseau : %s\n", 
            calcul( octetB, masqueB, 
                    reseau_buf, sizeof(reseau_buf) ) ) ;

请注意,最后一个版本也没有假设 masqueoctet 的长度 - 循环在所有输入中较短的一个处停止。如果它们不同,那是调用者的错误,函数实现将“优雅地”确定地失败,因此更容易调试。


除了对作业的解释

以上似乎都没有正确解决您似乎误解了的任务。我希望解决方案看起来像:

#include <stdio.h>
#include <stdint.h>

uint32_t subnet( uint32_t ip, uint32_t mask, char* subnet_str ) ;

int main()
{
    uint32_t ip = 0xC0A80001 ;      // 192.168.0.1
    uint32_t netmask = 0xFFFFFF00 ; // 255.255.255.0

    char ipstring[] = "000.000.000.000" ;
    printf( "0x%08X : ", subnet(ip, netmask, ipstring) ) ;
    printf( "%s\n", ipstring ) ;
}

uint32_t subnet( uint32_t ip, uint32_t mask, char* subnet_str )
{
    // Step 1 : apply mask to get subnet
    uint32_t network = ...

    // Step to: convert network to "xxx.xxx.xxx.xxx" string form
    // in subnet_str
    ...

    // Step 3
    return network ;
}

有输出:

0xC0A80000 : 192.168.1.0

显然有任何帮助都需要一个新问题。但是比您已经投入的工作要简单得多。步骤 1 和 2 都可以作为一行代码来实现。

【讨论】:

  • 对于那些期望调用者知道返回类型大小的函数,这是最佳选择。
  • @MartinJames:这里就是这种情况。我们这里只讨论这个问题。在其他情况下合适的方法当然可能会有所不同,但是隐藏malloc() 并将free() 责任留给更高级别的功能很少是一个好的设计,也很少需要。
  • '一个隐藏 malloc() 的函数' 哦,是的,这肯定很糟糕。如果需要,应注释返回动态的函数并提供析构函数并记录/注释。
猜你喜欢
  • 1970-01-01
  • 2021-10-22
  • 2012-07-04
  • 2012-05-03
  • 1970-01-01
  • 2021-01-07
  • 1970-01-01
  • 2017-05-30
  • 1970-01-01
相关资源
最近更新 更多