将字符串插入字符指针中的C语言操作

5

大家好,我正在尝试将一个string赋值给一个char *指针。下面是我的代码,但我收到这个警告:assignment makes integer from pointer without a cast.

在C语言中正确处理字符串的方式是什么?

char* protoName = "";

if(h->extended_hdr.parsed_pkt.l3_proto==0)
    *protoName = "HOPOPT";  
else if(h->extended_hdr.parsed_pkt.l3_proto==1)
    *protoName = "ICMP";    
else if(h->extended_hdr.parsed_pkt.l3_proto==2)
    *protoName = "IGMP";    
else if(h->extended_hdr.parsed_pkt.l3_proto==3)
    *protoName = "IGMP";    
else if(h->extended_hdr.parsed_pkt.l3_proto==4)
    *protoName = "IGMP";

char all[500];

sprintf(all,"IPv4','%s'",* protoName);

protoName与protoName [0]相同。单个字符无法保存字符串。因此,请使用protoName =“HOPOPT”; - dcaswell
那么,什么是改变它的最佳方式? - user2711681
protoName等于protoName [0]。那是一个单一的字符。你想改变protoName指向的位置。所以说protoName =“abcd”; - dcaswell
所以第一个char* protoName将其定义为指向char列表的指针,是吗?它可以是单个字符或多个字符,对吗? - user2711681
char *protoName 定义了一个指向字符的指针,名为 protoName。并不存在所谓的“字符列表”。该指针可以指向单个字符,也可以指向字符数组、字符串,并且对于所有这些组合,它都可以指向堆栈或堆上的内存。它还可以指向垃圾数据,但这是另一个问题的答案。 - Nik Bougalis
5个回答

8

如果您只想更改字符串常量protoName指向的内容,您只需要更改

*protoName = "HOPOPT";

to

protoName = "HOPOPT";
*protoName =试图写入protoName指向的第一个字符。在您的情况下,这是行不通的,因为protoName指向一个不能被修改的字符串常量。
您还需要更改sprintf调用方式。
sprintf(all,"IPv4','%s'", protoName);
%s 格式说明符表示您将传递一个指向以空字符结尾的char数组的指针。 *protoName 给出了由 protoName 指向的第一个字符的字符代码; sprintf 不知道这一点,因此会将该字符代码视为要读取的数组的地址。 您不拥有此内存,因此从中读取的效果将是未定义的,并且可能会导致崩溃。
另外,如果您有一个可写的char数组并想要更改其内容,则需要使用strcpy将新的字符数组复制到其中。

@那么可写的字符数组是什么?这不是*protoName对char列表的动态指针吗? - user2711681
一个可写的字符数组是指你已经分配了自己的内存,而不仅仅是指向别人内存的指针。char str[20]或者char* str = malloc(20)将会给你一个有20个字符空间的可写数组。 - simonc
2
@user2711681 不,protoName 是一个指向字符串字面量的指针(它不能被修改,应该被视为常量为空)。*protoName 是试图解引用指针 protoName 并将给出 protoName 指向的第一件事情。在这种情况下,一个 char,它将是 0。我不会绕弯子:如果你打算使用 C 语言,你必须理解数组、指针和字符串之间的区别,取地址符 '&' 和解引用 '*' 运算符的作用以及内存分配的工作原理。 - Nik Bougalis
@NikBougalis 我正在学习,当涉及到指针时,我感到非常困惑。数组我很清楚,因为它是固定的。 - user2711681
@user2711681 不需要改。如果你坚持使用 char* 并按照我建议的更改(除了旁注之外的所有内容),那么你的代码就很好了(实际上更正确)。旁注只是我认为你将来可能会发现有用的额外信息;我并不打算让你在当前程序中使用它。 - simonc
显示剩余16条评论

2

以下是一些示例:

#include <stdio.h>

const char * protoNameFromPktId(int id) {
    static char* protoName[] = { "HOPOPT", "ICMP", "IGMP", "IGMP","IGMP"};
    return protoName[id];
}

main() {
   printf("%s\n", protoNameFromPktId(2));
   char all[500];
   sprintf(all,"%s", protoNameFromPktId(2));
   strcpy(all, protoNameFromPktId(2));
}

这种情况下,第一个索引是0还是1?使用此方法和if else之间的速度差异是多少? - user2711681
它是零。它符合你的if-else条件。 - dcaswell
它不必重复测试任何东西。这只是一个查找。在运行时查找——同样有效——只是更清晰和更容易更改。 - dcaswell
3
if else 比数组索引要慢,但是将数组索引放在函数调用中可能会失去任何优势。也许编译器会内联它,也许不会,但你可以在函数中定义数组(虽然要将其定义为const static char *protoName[]),使用protoName[extended_hdr.parsed_pkt.l3_proto] 同样容易且自解释,就像protoNameFromPktId(extended_hdr.parsed_pkt.l3_proto)一样。 - Mike Housky
2
PS: unsigned id=extended_hdr.parsed_pkt.l3_proto; 然后 char *proto=(id < sizeof protoName / sizeof *protoName) ? protoName[id] : ""; 将防止无效或意外的协议值--就像你现在的 if/else if 链一样。 - Mike Housky
显示剩余2条评论

2

如果您正在使用常量,那么只需重新分配指针而不是内容:

const char* protoName = "";
if(h->extended_hdr.parsed_pkt.l3_proto==0)
    protoName = "HOPOPT";    
else if(h->extended_hdr.parsed_pkt.l3_proto==1)
    protoName = "ICMP";  
else if(h->extended_hdr.parsed_pkt.l3_proto==2)
    protoName = "IGMP";  
else if(h->extended_hdr.parsed_pkt.l3_proto==3)
    protoName = "IGMP";  
else if(h->extended_hdr.parsed_pkt.l3_proto==4)
    protoName = "IGMP";

为什么我需要定义为*protoName,但是分配只是protoName?这两者有什么区别吗? - user2711681
因为这就是 C 语言的工作方式。它与您最初的行 char *a = b; 相同,在每个其他操作中,您不需要一直添加 char *。这与 int x = 1; x = 2; 完全相同 -- 对于您的字符串,类型是 char * - Jongware
@user2711681,你感到困惑是因为在C语言中,*运算符有三种含义:它可以表示“乘法”,也可以表示“声明指针”,还可以表示“解引用指针”,而且你可能会在处理C语言中的字符串时遇到一些特殊情况。 - Nik Bougalis
@是的,你说得对,我在指针区域特别困惑*。 - user2711681

1
你只需要这样做:-
protoName = "HOPOPT"; 

代替

*protoName = "HOPOPT";

所以更改如下:

char* protoName = "";
  if(h->extended_hdr.parsed_pkt.l3_proto==0)
  protoName = "HOPOPT";    
  else if(h->extended_hdr.parsed_pkt.l3_proto==1)
  protoName = "ICMP";  
  else if(h->extended_hdr.parsed_pkt.l3_proto==2)
  protoName = "IGMP";  
  else if(h->extended_hdr.parsed_pkt.l3_proto==3)
  protoName = "IGMP";  
  else if(h->extended_hdr.parsed_pkt.l3_proto==4)
  protoName = "IGMP";

  char all[500];
    sprintf(all,"IPv4','%s'",* protoName);

1
我能看到的主要问题是您没有为字符串绑定内存,所以您必须使用malloc或更好地使用strdup函数自动分配内存。因为如果您分配了大字符串,那么就会出现问题。 其他人回答的警告问题已经解决,所以没事了。如果我错了,请纠正我。
char* protoName;
if(h->extended_hdr.parsed_pkt.l3_proto==0){
   protoName = strdup("HOPOPT");    
}
else if(h->extended_hdr.parsed_pkt.l3_proto==1){
  protoName = strdup("ICMP");  
...
char all[500];
sprintf(all,"IPv4','%s'",* protoName);
free(protoName);

1
不要忘记 free(protoName);。然而,复制一个常量字符串有什么意义呢? - trojanfoe
1
请注意,使用这种方法还需要一个最终的 else 块,以避免可能会由 sprintf 引用未初始化的 protoName - simonc
2
只要您理解代码的功能是什么,了解指针protoName所指向的内容以及如何使用它,那么像这样写char *protoName = ""; protoName = "ICMP";就完全没有问题。 - Nik Bougalis
为什么这里需要free? - user2711681

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接