首页 > 解决方案 > 在 CS50 库中使用字符串

问题描述

大家好,我有一个关于将字符串传递给 C 中的函数的问题。我正在使用 CS50 库,我知道他们将字符串作为 char 数组(指向数组开头的 char 指针)传递,因此传递是通过引用完成的。我的函数接收数组作为参数并返回数组。例如,当我更改函数中的数组元素之一时,此更改会按我的预期反映到原始字符串。但是如果我将新字符串分配给参数,函数会返回另一个字符串并且原始字符串不会改变。你能解释一下这种行为背后的机制吗?

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


string test(string s);

int main(void)
{
    string text = get_string("Text: ");
    string new_text = test(text);
    printf("newtext: %s\n %s\n", text, new_text);
    printf("\n");
    return 0;
}

string test(string s)
{
    //s[0] = 'A';
    s = "Bla";
    return s;
}

第一个示例反映了 text 和 newtext 字符串的第一个字母的变化,但第二个示例将 text 未更改并将 newtext 打印为“Bla” 谢谢!

标签: cstringcs50

解决方案


这需要一段时间。

让我们从基础开始。在 C 中,字符串是包含 0 值终止符的字符值序列。IOW,字符串 "hello"表示为 sequence {'h', 'e', 'l', 'l', 'o', 0}。字符串存储在数组中char(或wchar_t“宽”字符串,我们不会在这里讨论)。这包括字符串文字,例如"Bla"- 它们存储在数组中char,以便它们在程序的生命周期内可用。

在大多数情况下,“N-element array of”类型的表达式T将被转换(“decay”)为“pointer to T”类型的表达式,所以大多数时候我们在处理字符串时实际上是在处理带有类型的表达式char *。但是,这并不意味着类型的表达式char * 字符串 - achar *可能指向字符串的第一个字符,或者它可能指向不是字符串(无终止符)的序列中的第一个字符,或者它可能指向不属于较大序列的单个字符。

Achar *还可以指向已由 、 或 分配的动态分配缓冲区的开头。 malloccallocrealloc

另一件需要注意的是,[]下标运算符是根据指针算术定义的 - 表达式a[i]定义为*(a + i)- 给定地址值a(如上所述从数组类型转换),从该地址偏移i元素(不是字节)并取消引用结果。

另一个需要注意的重要事情是,=未定义将一个数组的内容复制到另一个数组。实际上,数组表达式不能成为=运算符的目标。

CS50string类型实际上是 type 的一个typedef(别名)char *。该get_string()函数在幕后执行了许多魔术来为字符串内容动态分配和管理内存,并使 C 中的字符串处理看起来比实际水平高得多。我和其他几个人认为这是教 C 的不好方法,至少在字符串方面是这样。不要误解我的意思,它是一个非常有用的实用程序,只是一旦你没有可用的 cs50.h 并且必须开始进行自己的字符串处理,你就会在海上呆一段时间。

那么,所有这些废话与您的代码有什么关系呢?具体来说,线

s = "Bla";

发生的事情是,不是将字符串文字的内容复制到指向"Bla"的内存,而是将字符串文字的地址写入,覆盖先前的指针值。您不能使用运算符将​​一个字符串的内容复制到另一个;相反,您必须使用如下库函数:ss=strcpy

strcpy( s, "Bla" );

之所以s[0] = A能按您的预期工作,是因为下标运算符[]是根据指针算术定义的。该表达式a[i]被评估为*(a + i)- 给定一个地址a(一个指针,或者一个如上所述“衰减”为指针的数组表达式),从该地址偏移i元素(不是字节!)并取消引用结果。s[0]指向您读入的字符串的第一个元素也是 如此。


推荐阅读