我试图理解如何用C语言以最干净/最安全的方式解决这个微不足道的问题。下面是我的例子:
#include <stdio.h>
int main(int argc, char *argv[])
{
typedef struct
{
char name[20];
char surname[20];
int unsigned age;
} person;
// Here I can pass strings as values...how does it work?
person p = {"John", "Doe", 30};
printf("Name: %s; Age: %d\n", p.name, p.age);
// This works as expected...
p.age = 25;
//...but the same approach doesn't work with a string
p.name = "Jane";
printf("Name: %s; Age: %d\n", p.name, p.age);
return 1;
}
编译器的错误是:
main.c:在函数'main'中:main.c:18:错误:从类型“char *”赋值给类型“char[20]”时不兼容的类型
我知道C(不是C++)没有String类型,而是使用char
s的数组,所以另一种方法是修改示例结构以保存char
s的指针:
#include <stdio.h>
int main(int argc, char *argv[])
{
typedef struct
{
char *name;
char *surname;
int unsigned age;
} person;
person p = {"John", "Doe", 30};
printf("Name: %s; Age: %d\n", p.name, p.age);
p.age = 25;
p.name = "Jane";
printf("Name: %s; Age: %d\n", p.name, p.age);
return 1;
}
这和预期的一样有效,但我想知道是否有更好的方法来做到这一点。
6条答案
按热度按时间gopyfrb31#
第一个例子不起作用,因为你不能给数组赋值--在这方面,数组的工作方式(有点)像常量指针。你可以做的是复制一个新值到数组中:
如果你事先知道字符串的最大大小,可以使用Char数组,例如。在第一个例子中,您100%确定名称将适合19个字符(而不是20个,因为总是需要一个字符来存储终止零值)。
相反,如果你不知道字符串的最大可能大小,或者你想优化内存使用,指针会更好。避免为名称“John”保留512个字符。但是,对于指针,您需要动态分配它们所指向的缓冲区,并在不再需要时释放它,以避免内存泄漏。
**更新:**动态分配缓冲区示例(使用您第二个示例中的struct定义):
qc6wkl3g2#
把字符串看作抽象对象,把char数组看作容器。字符串可以是任何大小,但容器必须至少比字符串长度大1(以容纳空终止符)。
C对字符串的语法支持很少。没有字符串运算符(只有字符数组和字符指针运算符)。您不能指定字符串。
但是你可以调用函数来帮助实现你想要的。
这里可以使用
strncpy()
函数。为了最大限度的安全,我建议遵循以下模式:另外,还可以看看
strncat()
和memcpy()
函数。hwamh0ep3#
这两个结构体是不同的。初始化第一个结构体时,将分配大约40个字节的内存。当你初始化第二个结构时,大约分配了10个字节的内存。(实际金额取决于体系结构)
可以使用字符串文字(字符串常量)初始化字符数组。这就是为什么
person p = {“John”,“Doe”,30};
在第一个例子中工作。
在C语言中不能赋值(传统意义上的)字符串。
当代码执行时,您拥有的字符串字面量(“John”)将加载到内存中。当你用这些文字初始化一个数组时,字符串被复制到一个新的内存位置。在第二个示例中,您只是将指针复制到字符串字面量(的位置)。做一些类似的事情:
可能会导致编译或运行时错误(我不确定)。这是一个坏主意,因为你正在修改文字字符串“Hello”,例如在微控制器上,它可能位于只读存储器中。
ifsvaxew4#
第一个结构体是字符数组[],第二个结构体是指向字符串的指针 *(对于64位机器,大小为8字节)。根据Stephen Kochan的书“Programming in C”,C允许您分配常量字符串的唯一时间是在定义和初始化char数组时,如
甚至没有
在char *name的情况下name是字符指针,而不是数组。当你做了
它指向另一个字符串对象。
输出:
但是,在字符数组[]的情况下,在执行
为了改变其内容,缓冲区p.name[]的地址永远不会改变。
C和Python之间一个有趣的相似之处是Python的String是不可变的,类似于C的字符串指针,其中字符串文字是只读的。Python的List是可变的,类似于C的字符数组。
9nvpjoqh5#
在这两种情况下,你都在写:
p.name
是一个数组,在C语言中无法对数组赋值p.name
是一个char*
,并且可以将其分配给字符串文字,因为字符串文字是char
的数组(数组可以转换为指针)您可以使用
strcpy
、memcpy
等函数。如其他响应中所示,但您也可以通过分配整个struct
来规避此问题。在实践中,将字符串作为
char*
和size_t
捆绑在一个struct
中是很有用的,因此通常也可以对单个字符串这样做。tzdcorbm6#
下面是一个如何实现安全字符串赋值的示例。如果字符串比目标数组长,则Assert失败,程序退出。