我现在正在努力学习C语言,我来自Java,有些东西对我来说很新。
我想打印一个字符串并将一个int和一个字符串(char数组)发送到另一个方法。但我不断得到一些我不知道如何解决的错误。
如果有人可以花时间向我解释我的代码中有什么问题,我们将非常感激。我用这些指针迷失方向。何时在打印等时使用%s和%c ...
代码:
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
string = "hello!";
int *ptr;
sptr = &string;
ptr = &k;
printf("%s \n", &sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}
错误。
test.c: In function ‘main’:
test.c:8:9: warning: assignment makes integer from pointer without a cast
test.c:15:2: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char **’
tezt.c: In function ‘sendptr’:
tezt.c:8:8: error: incompatible types when assigning to type ‘char[6]’ from type ‘char’
感谢您的时间! :)
首先解决了这些问题。
第二个功能我得到了这个......
tezt.c: In function ‘sendptr’:
tezt.c:5:2: error: invalid initializer
#include <stdio.h>
void sendptr(int *test, char *fname)
{
char fnamn[] = &fname;
int pt;
pt = *test;
printf("%p \n", test);
printf("%d \n", pt);
printf("%s \n", fnamn);
}
答案 0 :(得分:2)
char string;
string = "hello!";
第一个问题:您将string
声明为单个字符,而不是数组。此外,您只能在单个语句中将数组初始化为字符串文字。
char string[] = "hello!";
第二个问题:sptr
是一个指向char的指针,因此它必须指向字符串的第一个元素。其中任何一个都可以:
char *sptr = string;
char *sptr = &string[0];
然后,在打印字符串时,只需直接传递sptr
。
printf("%s \n", sptr);
编辑以获取下一个问题。
char fnamn[] = &fname;
您正在尝试将char**
(指向char的指针)指定给数组。那是行不通的。如果要将fname
指向的字符串复制到fnamn
,则需要使用strncpy
等函数。
char fnamn[MAX_STRING_SIZE];
strncpy(fnamn, fname, MAX_STRING_SIZE);
话虽如此,如果你只是想打印字符串,那么直接打印fname
而不先将其复制到你的数组中。
答案 1 :(得分:1)
首先,我建议改变:
char string;
为:
char *string;
很明显,您希望string
变量是字符串而不是单个字符。
此外,您可能想要更改两行:
sptr = &string;
printf("%s \n", &sptr);
为:
sptr = string;
printf("%s \n", sptr);
但您也可以将string
本身传递给printf
。
至于sendptr(ptr, sptr);
,如果不了解更多细节,我们就无法帮助你。
要修复您的第二个功能(来自您的编辑),请更改:
char fnamn[] = &fname;
为:
char *fnamn = fname;
或直接使用fname
。你没有拥有来制作指针的副本,而前者用于以下内容:
char fnamn[] = "I am a string literal";
答案 2 :(得分:1)
以下是带有一些注释的程序的更正版本:
#include <stdio.h>
int main(void) // int and (void) for standard mains.
{
int k = 10;
char *string; // a C string is a char array, you need a pointer to point to it
char *sptr;
int *ptr;
string = "hello!";
sptr = string;
ptr = &k;
printf("%s \n", sptr); // no &. The %s format expects a char*.
printf("Sending pointer.\n");
// sendptr(ptr, sptr); // don't know what this function is, ignoring
return 0;
}
答案 3 :(得分:1)
在C语言中,&
运算符意味着您要使用变量的地址(即&amp; =“变量的地址”)。
int an_integer=2; // an_integer is a memory part where you want to store 2 ;)
printf("%d", &an_integer); // here you will print the address of the memory part where an_integer is stored (not 2, more something like 2510849).
变量声明中的*
运算符意味着你想要一个指向内存部分的指针,当在代码中使用它时,它意味着“地址包含的值”
int an_integer=2;
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = &an_integer; // here you set the pointer ptr_integer to the address of an_integer
printf("%d", *ptr_integer); // here you print the value contained at the memory address stored in the ptr_integer
[]
运算符意味着您要存储某个数组。在C中,数组可以看作是指向内存空间的指针。
int an_integer[2]; // you declare an array of 2 integers
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = (int *)an_integer; // here you set the value of the pointer to the address of the array, you have to cast it into an (int *) to avoid compilation warnings.
答案 4 :(得分:1)
我认为添加一些关于char数组和指向字符串的指针之间差异的东西可能会有所帮助。
在下面的function1中,局部变量 stringPtr 是一个指向内存的指针,其中包含字符串“hello!”。包含此字符串的内存将位于程序的只读部分。编译器决定将字符串“hello!”放在何处!并确保使用此内存地址初始化本地变量。
您可以修改指针 stringPtr 并将其更改为指向其他位置。但你无法修改它所指向的记忆。
此外,即使它是一个指针,使用数组访问符号 stringPtr [2] 也是完全有效的。
在function2中,编译器将在堆栈上为局部变量 stringArray 留出9个字节的空间,并确保使用字符串“Goodbye!”初始化此数组。由于此内存位于堆栈中,您可以修改数组的内容。
#include <stdio.h>
void function1(void)
{
char *stringPtr = "hello!";
printf("The first char is %c\n", stringPtr[0]);
printf("The next char is %c\n", *(stringPtr+1));
// This would cause a segmentation fault, stringPtr points to read-only memory
// stringPtr[0] = 'H';
}
void function2(void)
{
char stringArray[] = "Goodbye!";
printf("The first char is %c\n", stringArray[0]);
}
int main(void)
{
function1();
function2();
return 0;
}
答案 5 :(得分:1)
首先,main
的返回类型应为int
,而不是void
。如果编译器文档显式将其列为合法签名,则void main()
只能定义良好。否则,您将调用未定义的行为。请改用int main(void)
。
其次,是时候对字符串,数组和指针进行快速速成课程了。
与Java不同,C没有专用的字符串数据类型;相反,字符串表示作为由{0}终止的char
值的序列。它们存储作为char
的数组。字符串文字“hello”存储为char
(C ++中的const char
)的6元素数组。此数组具有静态范围,这意味着它在程序启动时分配并保持到程序终止。试图修改字符串文字的内容会调用未定义的行为;最好表现得好像是不可写的。
当数组表达式出现在大多数上下文中时,表达式的类型将从“N元素数组T”转换为“指向T”,表达式的值是第一个元素的地址。阵列。这是string = "hello";
语句不起作用的原因之一;在该上下文中,表达式"hello"
的类型从“{元素char
的6元素数组”转换为“指向char
的指针”,这与目标类型不相容(是char
,不是正确的类型)。此规则的唯一例外是当数组表达式是sizeof
或一元&
运算符的操作数时,或者它是一个字符串文字用于初始化声明中的另一个数组。
例如,声明
char foo[] = "hello";
将foo
分配为char
的6元素数组,并将字符串文字的内容复制到其中,而
char *bar = "hello";
将bar
指定为char
的指针,并将字符串文字的地址复制到其中。
如果要将一个阵列的内容复制到另一个阵列,则需要使用strcpy
或memcpy
等库函数。对于字符串,您可以使用strcpy
,如下所示:
char string[MAX_LENGTH];
strcpy(string, "hello");
您需要确保目标足够大以存储源字符串的内容以及终止0.否则您将获得缓冲区溢出。 C中的数组不知道它们有多大,超过数组的结尾不会像在Java中那样引发异常。
如果您想防止缓冲区溢出的可能性,您可以使用strncpy
,它将计数作为附加参数,以便复制不超过N个字符:
strncpy(string, "hello", MAX_LEN - 1);
问题是如果源长于目标,strncpy
将不会将0终止符附加到目标;你必须自己做。
如果要打印字符串的内容,可以使用%s
转换说明符并传递一个表达式,该表达式的计算结果为字符串第一个元素的地址,如下所示:
char string[10] = "hello";
char *p = string;
printf("%s\n", "hello"); // "hello" is an array expression that decays to a pointer
printf("%s\n", string); // string is an array expression that decays to a pointer
printf("%s\n", p); // p is a pointer to the beginning of the string
同样,"hello"
和string
的类型都将其从“{元素数组char
”转换为“指向char
的指针”;所有printf
看到的都是指针值。
这是一个方便的表格,显示涉及数组的各种表达式的类型:
Declaration: T a[M]; Expression Type Decays to ---------- ---- --------- a T [M] T * &a T (*)[M] *a T a[i] T &a[i] T * Declaration: T a[M][N]; Expression Type Decays to ---------- ---- --------- a T [M][N] T (*)[N] &a T (*)[M][N] *a T [N] T * a[i] T [N] T * &a[i] T (*)[N] *a[i] T a[i][j] T &a[i][j] T *
请记住,一元&
运算符将产生其操作数的地址(假设操作数是左值)。这就是为什么你的char fnamn[] = &fname;
声明会抛出“无效的初始化程序”错误;您正尝试使用指针值初始化char
数组的内容。
一元*
运算符将产生其操作数指向的值。如果操作数未指向任何有意义的位置(它是NULL或与有效地址不对应),则行为未定义。如果你很幸运,你会直接得到一个段落错误。如果你不幸运,你会得到奇怪的运行时行为。
请注意,表达式a
和&a
会产生相同的值(数组中第一个元素的地址),但它们的类型不同。第一个产生一个指向T的简单指针,其中第二个产生一个指向T数组的指针。当你进行指针运算时,这很重要。例如,假设以下代码:
int a[5] = {0,1,2,3,4};
int *p = a;
int (*pa)[5] = &a;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
p++;
pa++;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
对于第一个printf
,两个指针值是相同的。然后我们推进两个指针。 p
将提前sizeof int
个字节(即,它将指向数组的第二个元素)。 pa
,OTOH,将提前sizeof int [5]
个字节,以便它指向数组末尾的第一个字节。
答案 6 :(得分:0)
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
sptr = "hello!";
int *ptr;
ptr = &k;
printf("%s \n", sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}