我在3年多的时间里没有使用过C,我在很多方面都很生气。
我知道这可能看起来很愚蠢但我现在无法从函数返回一个字符串。请假设:我不能使用string.h
。
这是我的代码:
#include <ncurses.h>
char * getStr(int length)
{
char word[length];
for (int i = 0; i < length; i++)
{
word[i] = getch();
}
word[i] = '\0';
return word;
}
int main()
{
char wordd[10];
initscr();
*wordd = getStr(10);
printw("The string is:\n");
printw("%s\n",*wordd);
getch();
endwin();
return 0;
}
我可以捕获字符串(使用我的getStr
函数),但我无法正确显示它(我得到了垃圾)。
帮助表示赞赏。
答案 0 :(得分:50)
在调用者端的堆栈上分配字符串并将其传递给您的函数:
void getStr(char *wordd, int length) {
...
}
int main(void) {
char wordd[10 + 1];
getStr(wordd, sizeof(wordd) - 1);
...
}
或者在getStr
中将字符串设为静态:
char *getStr(void) {
static char wordd[10 + 1];
...
return wordd;
}
或者在堆上分配字符串:
char *getStr(int length) {
char *wordd = malloc(length + 1);
...
return wordd;
}
答案 1 :(得分:8)
char word[length];
char *rtnPtr = word;
...
return rtnPtr;
这不好。您正在返回一个指向自动(范围)变量的指针,该变量将在函数返回时被销毁。指针将指向一个被破坏的变量,这几乎肯定会产生&#34;奇怪的&#34;结果(未定义的行为)。
您应该使用malloc
分配字符串(例如char *rtnPtr = malloc(length)
),然后free
稍后再main
。
答案 2 :(得分:3)
您正在堆栈上分配字符串,然后返回指向它的指针。当函数返回时,任何堆栈分配都将失效;指针现在指向堆栈上可能在下次调用函数时被覆盖的区域。
为了完成您尝试做的事情,您需要执行以下操作之一:
malloc
或类似内容在堆上分配内存,然后返回该指针。然后,调用者需要在完成内存时调用free
。答案 3 :(得分:2)
您的指针指向函数的局部变量。因此,只要从函数返回,内存就会被释放。您必须在堆上分配内存才能在其他函数中使用它。
相反
char *rtnPtr = word;
这样做
char *rtnPtr = malloc(length);
因此它在main函数中可用。使用后释放内存。
答案 4 :(得分:1)
word
位于堆栈中,只要getStr()
返回就会超出范围。您正在调用未定义的行为。
答案 5 :(得分:1)
正如其他人已经说过的,如果不将非常量字符串分配到堆上(例如使用 strdup),就不能以有用的方式返回它。但是在 C 标准的所有最新版本(C89 和更高版本,如果我没记错的话)中,您可以返回一个结构体。调用者不需要释放结果,因为它不在堆上。而且它是线程安全的。
#include <stdio.h>
struct stringbuf
{
char buf[40];
};
struct stringbuf getanswer(int i)
{
struct stringbuf result = { 0 };
snprintf(result.buf, sizeof(result.buf), "The answer is %d", i);
return result;
}
int main(int argc, char **argv)
{
/*
* Remember to pass the .buf member, not the struct, to functions
* such as printf which expect a character pointer as argument!
* Passing the result of getanswer in the next line without .buf
* appended, will likely crash the program because the program
* will put the entire struct on the stack, not a character
* pointer, and will make printf interpret the first few bytes
* of the string as a pointer. That would be bad.
*/
printf("How many arguments did I get? %s\n", getanswer(argc).buf);
return 0;
}
注意:为了使示例代码尽可能简单和集中,我只是声明了一个没有 typedef 的结构类型。您可以通过使用 typedef 并返回定义的类型来节省大量输入。
有(可以说)一些缺点:
最后一点很重要,因为您必须记住,带有字符数组的结构与数组本身不同。因此,如果要调用字符串函数,则应传递字符串成员变量,而不是指向结构的指针。这对于具有可变参数的函数(例如 printf 和朋友,如果您做错了编译器可能不会警告您)尤其重要:传递结构会将整个结构放在堆栈上,而不仅仅是指向第一个字符的指针。 printf 会将 struct 中的前几个字符解释为字符指针,这肯定是无效的。
是的,可以将指向结构的指针转换为 char * 并将其传递给字符串函数(包括 printf),这将正常工作,但我认为这样做是不好的做法:如果您(或其他人)曾经决定将另一个成员变量放在字符串缓冲区前面的结构声明中,任何使用指向结构的类型转换指针(假设字符串缓冲区从结构开始的地方开始)都会悄悄 em> 失败。你可能想避免这种情况,所以即使有点不方便,也要使用指向字符串成员变量的指针。
===杰克
答案 6 :(得分:0)
更简单:返回一个指向字符串的指针,该字符串与strdup一起使用。
#include <ncurses.h>
char * getStr(int length)
{
char word[length];
for (int i = 0; i < length; i++)
{
word[i] = getch();
}
word[i] = '\0';
return strdup(&word[0]);
}
int main()
{
char wordd[10];
initscr();
*wordd = getStr(10);
printw("The string is:\n");
printw("%s\n",*wordd);
getch();
endwin();
return 0;
}
答案 7 :(得分:0)
在研究我对Cython的理解时,我遇到了这个问题。我对原始问题的扩展可能对在C / Cython界面上工作的其他人有用。所以这是原始问题的扩展:如何从C函数返回一个字符串,使其可用于Cython&amp;因此对于Python?
对于那些不熟悉它的人,Cython允许你静态输入你需要加速的Python代码。所以这个过程是,喜欢编写Python :),在某个地方找到它有点慢,对它进行分析,对一个或两个函数进行生成并对它们进行cython化。哇。接近C速度(它编译为C)固定。好极了。另一种用途是将C函数或库导入到Python中。
这将打印一个字符串并将相同或另一个字符串返回给Python。有3个文件,c文件c_hello.c,cython文件sayhello.pyx和cython安装文件sayhello.pyx。当使用python setup.py build_ext --inplace
编译它们时,它们会生成一个可以导入python或ipython的共享库文件,并运行sayhello.hello函数。
c_hello.c
#include <stdio.h>
char *c_hello() {
char *mystr = "Hello World!\n";
return mystr;
// return "this string"; // alterative
}
sayhello.pyx
cdef extern from "c_hello.c":
cdef char* c_hello()
def hello():
return c_hello()
setup.py
from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
ext_modules = cythonize([Extension("sayhello", ["sayhello.pyx"])])
setup(
name = 'Hello world app',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)