如何解决有没有一种方法可以创建变量的副本,以使原始变量在函数中不发生变化?
我目前正在处理CS50中的替换问题,并且我的变量在代码中的行为方式存在问题。 基本上我得到了两个变量plain_text和key_2。我的问题是那两个变量,尽管事实上我正在创建它们的副本,以便它们不会更改,但仍不断为其分配副本所获得的值。现在我知道它在某种程度上与变量的范围有关,但是我只是想不出如何正确地做到这一点,所以在变量的副本更改而不是原始的情况下。
#include <stdio.h>
#include <math.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
string substitute_strings (string plain_text,string key);
int main (int argc,string argv[])
{
for (int i = 0; i < argc; i++)
{
if (argc == 1)
{
printf ("Enter key!\n");
return 1;
}
for (int j = 0; j < strlen (argv[1]); j++)
{
if ((argv[1][j] >= 'a' && argv[1][j] <= 'z') || (argv[1][j] >= 'A' && argv[1][j] <= 'Z'))
{
int var = 0;
}
else
{
printf ("Key can contain only alphabet!");
return 1;
}
}
if (strlen(argv[1]) != 26)
{
printf ("Key must contain 26 characters!\n");
return 1;
}
for (int c = 0; c < strlen (argv[1]); c++)
{
for (int b = c + 1; b < strlen (argv[1]);b++)
{
if (argv[1][c] == argv[1][b])
{
printf ("Character cannot repeat twice in key!");
return 1;
}
}
}
}
string key = argv[1];
string plain_text = get_string ("Enter messege here: \n");
printf("ciphertext: %s\n",substitute_strings (string plain_text,string key));
return 0;
}
**string substitute_strings (string plain,string key_2)**
{
string alphabet_upper = "ABCDEFGHIJKLMnopQRSTUVWXYZ";
string alphabet_lower = "abcdefghijklmnopqrstuvwxyz";
string plain_copy = plain;
for (int m = 0; m < strlen (plain_copy); m++)
{
if (plain_copy[m] >= 'A' && plain_copy[m] <= 'Z')
{
int exit_loop = 0;
for (int n = 0; exit_loop < 1;n++)
{
if (alphabet_upper[n] == plain_copy[m])
{
plain_copy[m] = key_2[n];
exit_loop++;
}
}
}
else if (plain_copy[m] >= 'a' && plain_copy[m] <= 'z')
{
int h = 0;
string key_2_copy = key_2;
while (h < strlen (key_2))
{
key_2_copy[h] = tolower(key_2_copy[h]);
h++;
}
int exit_loop_2 = 0;
int p = 0;
while (exit_loop_2 < 1)
{
if (alphabet_lower [p] == plain_copy [m])
{
plain_copy[m] = key_2_copy [p];
exit_loop_2++;
}
p++;}
}
}
return plain_copy;
}
解决方法
string
是char*
的别名,指针实际上已被复制。
要复制指向的字符串,您应该分配一个内存并使用strcpy()
。
#include <stdlib.h>
应添加到代码顶部以使用malloc()
(和exit()
)和
string plain_copy = plain;
应该是
string plain_copy = malloc(strlen(plain) + 1); /* +1 for terminating null-character */
if (plain_copy == NULL) { /* check if allocation is successful */
perror("malloc");
exit(1);
}
strcpy(plain_copy,plain);
,
CS50库在这里很容易出错,因为它严重误解了C语言处理字符串的方式。简而言之,string
typedef名称是一个谎言,因为它的别名是不是字符串。感到舒适,这将需要一段时间。
首先,一些必要的背景...
C没有真正的带有自己的语义和运算符的字符串数据类型-在C中,字符串只是包含0值终止符的字符值序列,因此像"foo"
这样的字符串表示为序列'f','o',0
。字符串存储在字符类型的数组中(char
或wchar_t
用于“宽”字符编码),但是您也可以存储不是 字符串的字符序列(字符类型数组中没有0终止符。
除非它是sizeof
或一元&
运算符的操作数,或者是用于初始化声明中的字符数组的字符串文字,否则类型为{的N元素数组{1}}”将被转换或“衰减”为类型为“ T
的指针”的表达式,该表达式的值将是字符串的第一个元素的地址。除其他外,这意味着当您将数组表达式传递给函数时,该函数实际接收的是指向数组第一个元素的指针:
T
我们在记忆中得到的是这样的:
void foo( char *str )
{
// do something with str
}
int main( void )
{
char string[] = "hello"; // array size is taken from length of string + 1
foo( string );
...
}
+---+
str: | |---------------+
+---+ |
... |
+---+ |
string: |'h'| string[0] <---+
+---+
|'e'| string[1]
+---+
|'l'| string[2]
+---+
|'l'| string[3]
+---+
|'o'| string[4]
+---+
| 0 | string[5]
+---+
不包含字符串本身,它包含存储字符串的缓冲区的地址。对于所有数组类型,不仅是包含字符串的数组,这种行为是相同的。
其结果是,当我们处理字符串时,大多数时候我们都在处理str
类型的表达式。但是char *
不是字符串-它可能指向字符串的第一个字符,或者可能指向不属于字符串的序列的第一个字符不是字符串(没有终止符),或者它可能指向不属于较大序列的单个char *
对象。
好的,这就是背景。那么,所有这些如何应用于您的代码?
CS50库在后台执行各种魔术操作,使您与I / O和内存管理的繁琐细节隔离开来。 char
函数提示用户输入,动态地 分配内存来存储输入的字符串,并向该动态缓冲区返回 pointer :
get_string
CS50库引入了typedef名称char *str = malloc( SOME_SIZE );
// get string from input and save to this buffer
return str;
作为类型string
的别名。这意味着char *
类型的对象实际上是指针,而不是字符串。
因此,当您将string
的结果分配给get_string
时,内存中的内容是这样的(假设输入为plain_text
)
"foo"
因此 +---+
plain_text: | | ----+
+---+ |
... |
+---+ |
|'f'| <---+
+---+
|'o'|
+---+
|'o'|
+---+
| 0 | <-- string terminator
+---+
本身并不存储字符串,而是存储包含字符串的缓冲区的地址。当您将plain_text
传递给plain_text
时,它只是接收此指针值,而不是字符串的副本。
写作时
substitute_strings
您要将缓冲区的地址复制到plain_copy = plain;
中,因此plain_copy
和 plain
都指向相同的内存:
plain_copy
您对缓冲区所做的任何更改都会同时反映在 +---+
plain_copy: | | -------+
+---+ |
... |
+---+ |
plain: | | ----+ |
+---+ | |
... | |
+---+ | |
|'f'| <---+--+
+---+
|'o'|
+---+
|'o'|
+---+
| 0 |
+---+
和plain
中。
那么您如何解决这个问题?
在您的plain_copy
函数中,您将需要分配另一个相同大小的缓冲区,并将其地址分配给substitute_strings
,然后将plain_copy
的内容复制到该新缓冲区中:
plain
现在您遇到以下情况:
string plain_copy = malloc( strlen( plain ) + 1 );
if ( plain_copy )
strcpy( plain_copy,plain );
else
// unable to allocate memory for copy,handle as appropriate
// manipulate and return plain_copy as before
+---+
plain: | | ----+
+---+ |
... |
+---+ |
|'f'| <---+
+---+
|'o'|
+---+
|'o'|
+---+
| 0 |
+---+
+---+
plain_copy: | | ----+
+---+ |
... |
+---+ |
|'f'| <---+
+---+
|'o'|
+---+
|'o'|
+---+
| 0 |
+---+
和plain
现在指向两个不同的字符串,因此对一个字符串的更改不会影响另一个字符串。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。