在C函数中返回char数组
我一直在写一个非常小的C程序,我遇到了很多问题。通过我可以找到的所有堆栈溢出文章来看,但没有取得太大的成功。该程序假设对纯文本字符串使用非常简单的异或“加密”。输入字符串和键都是6个字符长。我是C和指针的新手。我认为我没有掌握一些语言的基础知识。在C函数中返回char数组
#include <stdio.h>
#include <string.h>
#define LENGTH 7
#define KEY "secret"
char * encryptDecrypt(char *plaintext);
int main(int argc, char **argv)
{
if(argc > 1)
{
char *plainText = argv[1];
printf("Encrypting plaintext: %s (%i)\n", plainText, strlen(plainText));
char *cipherText = encryptDecrypt(plainText);
printf("Encrypted: %s (%i)\n", cipherText, strlen(cipherText));
char *decryptedText = encryptDecrypt(cipherText);
printf("Decrypted: %s (%i)\n", decryptedText, strlen(decryptedText));
}
return 0;
}
char * encryptDecrypt(char *text)
{
char result[LENGTH];
for (int i = 0; i < LENGTH-1; i++)
{
result[i] = (char)(text[i]^KEY[i]);
}
char *resultPtr = &result;
return resultPtr;
}
用Arg “foobar的” 输出运行程序:
加密明文:foobar的(6)
加密:╠╠╠╠╠╠╠╠T¨(19)
解密的:╠╠╠╠╠╠╠╠T¨(19)
问题:
- 打印指向结果数组的指针在encryptDecrypt函数中使用并返回后,会有所不同
- 在密文上使用XOR不会将其还原为原始纯文本(尽管因为无论我的' m打印错误,这部分可能没有问题)
- 加密/解密文本的字符串长度是19个字符长吗?如果原始字符串是6个字符,这怎么可能?
char *resultPtr = &result;
return resultPtr;
你不能这样做。 result
函数结束时不存在,则不能返回result
。
修改你的函数是这样的:
void encryptDecrypt(char *text, char *result)
{
for (int i = 0; i < LENGTH - 1; i++)
{
result[i] = (char)(text[i]^KEY[i]);
}
}
创建在调用者网站的数组,然后将其作为result
。例如
char result[LENGTH] = {0};
encryptDecrypt(plainText, result);
注意:实际使用%s
打印加密的数据是不是最好的主意,因为例如作为XOR的结果,你可能会在文本之间的空字节,这将被视为您的字符串为空终止符,并且printf
不会显示其余字符串。考虑用于打印密文的东西如this。
您的格式说明符strlen
也是错误的,请使用%zu
insted %i
,否则您将触发undefined behaviour。
会使用'char ** result'作为指针处理的更多保存方式吗?我不太确定,如果'char * result'将起作用。顺便说一句:使用'malloc'将解决问题。 – LittleByBlue
@LittleByBlue它会以它的方式工作,你可以测试。没有malloc,我已经避免了内存管理问题,因为OP假定了固定大小。 –
'char * resultPtr =&result;'是无效的,因为'&result'的类型是'char **'。 – LittleByBlue
你不能返回一个指向局部变量的指针。你必须要么
- 传递一个缓冲区的地址
- malloc的空间,并返回它(然后调用者必须释放它)
- 的strdup局部变量和返回(这实际上就是的malloc结束了你)
你不能返回一个指向局部变量的原因是因为当你退出功能,他们被摧毁
'strdup()'不会在'result'上工作。 'strdup()'依赖空字符表示结束。 'result [i] =(char)(text [i]^KEY [i]);'打破合同。需要malloc /复制'LENGTH'或'LENGTH + 1'。 – chux
你encryptDecrypt
是返回一个局部变量的地址。一旦函数返回,该内存无效,因此试图使用它是undefined behavior。
您应该使用malloc
为该功能的结果动态分配内存。此外,您应该传递字符串的大小,以便知道需要分配多少空间。
将加密的字符串打印为字符串也是未定义的行为,因为您拥有的不是一个字符串,而是一个不以null结尾的字符数组。
另外,打印sizeof
的结果时,请务必使用%zu
格式说明符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LENGTH 7
#define KEY "secret"
char * encryptDecrypt(char *text, int len);
int main(int argc, char **argv)
{
if(argc > 1)
{
char *plainText = argv[1];
// use the string length + 1 to include the null terminator
int len = strlen(plainText)+1;
printf("Encrypting plaintext: %s (%zu)\n", plainText, strlen(plainText));
char *cipherText = encryptDecrypt(plainText,len);
//printf("Encrypted: %s (%zu)\n", cipherText, strlen(cipherText));
char *decryptedText = encryptDecrypt(cipherText,len);
printf("Decrypted: %s (%zu)\n", decryptedText, strlen(decryptedText));
// clean up the allocated memory
free(cipherText);
free(decryptedText);
}
return 0;
}
char * encryptDecrypt(char *text, int len)
{
char *result = malloc(len); // allocate memory for the result
for (int i = 0; i < len; i++)
{
// if the text is longer that the key, wrap around on the key
result[i] = (char)(text[i]^KEY[i%LENGTH]);
}
return result; // return the allocated buffer
}
编辑:
修正了KEY
索引,以防止overruning它。
没有downvote,但我认为它是空终止,检查,他只加密前6个字母 –
@GiorgiMoniava我在'strlen(plainText)+ 1'传递的加密/解密长度,以便空终止符将被拾取向上。这样,它不依赖于字符串的长度,并且它不需要在解密后手动将null终止。 – dbush
我没有批评你的代码 - 我说他的空终止,即使加密我猜 –
encryptDecrypt函数中的结果字符数组仅是此函数的局部变量,只要encryptDecrypt函数正在执行,它的内容将保留在内存中。一旦函数执行完成,数组的结果内容可能会或可能不会出现在内存中(如果内容被破坏,那么它将包含一些垃圾值)。
数组名称本身指向数组的第一个元素。
因此char *resultPtr = &result;
正在发送指向第一个元素的指针地址。 相反,你应该写char *resultPtr = &result[0];
或char *resultPtr = result;
为了使您的代码的工作,取代char result[LENGTH];
与
char * result = (char*)malloc(sizeof(LENGTH));
result[LENGTH-1] = '\0'; // To make result string null terminated
malloc函数用于动态内存分配,现在出现在结果数组中的内容将保持在内存中(甚至在函数执行结束后),直到使用自由函数从内存中明确释放。
注:即使加密后的结果字符串为空终止,但我们不能用printf("%s",result);
打印,因为加密方法使用XOR甚至可以使字符串作为空terrminator的其他字符。要打印这样的字符串,您必须创建自己的函数来打印结果数组的前6个字节。
'(char *)'cast不是必要的,因为'malloc'返回'void *'。但很好的答案。 – LittleByBlue
只能用malloc替换不会有帮助,请参阅dbush的回答。在OPs情况下,第7个字节不是空的。 –
“数组结果竞赛被销毁(它会包含一些垃圾值)”--->确信C没有指定这个。在函数结束后使用'&result'就是UB。数据可能在那里,可能不是。 – chux
'char result [LENGTH]; ... char * resultPtr =&result;返回resultPtr;'。不可以。您不能返回本地变量的地址。这是未定义的行为。 –
[指向本地变量的指针]的可能重复(http://stackoverflow.com/questions/4570366/pointer-to-local-variable) – 2501
安全注意事项:1)在使用它们后清理纯文本缓冲区memset(decryptedText ,0,its_size)'2)使用'strdup()'复制plaint文本数据是针对#1的一个问题。最好只在处理纯文本数据时使用自己的代码,而不是在内存中放置它的潜在副本。 – chux