在我的程序中,我试图将每个argv [i]复制到关键字[i],但我的程序因分段错误而失败。我做错了什么?
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
int main(int argc, string argv[])
{
//prototype
string keyword = "";
//int j;
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
keyword[i] = toupper(argv[1][i]);
printf("%i-- printing letters\n", keyword[i]);
}
}
答案 0 :(得分:4)
正如其他人所观察到的,您将变量keyword
初始化为空字符串或指向空字符串文字的指针,具体取决于类型string
的定义。无论哪种方式,只有keyword[i]
评估等于零的i
才有效;任何其他值 - 用于读或写 - 都超出范围。此外,在后者(指向字符串文字的指针)的情况下,您不能尝试修改数组keyword
指向。
特别注意,如果您尝试访问越界元素,C不会自动扩展字符串。相反,尝试这样做会产生“未定义的行为”,并且在这种情况下表现出来的常见方式是以分段错误的形式出现。当系统打下你的程序试图访问不属于它的内存时,你可以查看分段错误。
由于您不知道先验参数字符串复制前的长度,keyword
最可行的类型是char *
。为清楚起见,我将在后面的内容中使用该类型而不是string
。
如果您确实想要复制参数,那么到目前为止最简单的方法是通过for-purpose函数strdup()
:
char *keyword = strdup(argv[1]);
为其参数的副本分配足够的内存,包括终结符,复制它,并返回指向结果的指针。然后,当您完成后,您必须通过free()
函数释放生成的内存。以这种方式制作副本后,您可以将每个元素放在原位:
for (int i = 0, n = strlen(keyword); i < n; i++)
{
keyword[i] = toupper(keyword[i]);
printf("%c-- printing letters\n", keyword[i]);
}
顺便提一下,请注意,单个字符的printf()
格式描述符为%c
,而不是%i
。您必须使用它将字符打印为字符,而不是它们的整数值。
这是为您尝试做的事情编写C代码的最简单方法之一,尽管有很多变化。我提供给你考虑的唯一另一个是不复制参数:
char *keyword = argv[1];
如果以这种方式初始化keyword
,则不分配任何内存或进行复制;相反,您将keyword
设置为指向argv[1]
指向的相同字符串。您可以就地修改该字符串(但不能延长它),前提是您不需要保留其原始内容。
在我把它包起来之前,我还应该观察到你的程序没有检查是否确实存在参数。如果没有( ie argc < 2
),argv[1]
要么包含空指针(argc == 1
)要么未定义(argc == 0
;你不太可能碰到这个)。无论哪种方式,如果程序尝试使用argv[1]
,就好像它是指向有效字符串的指针,那么程序会产生未定义的行为。您应首先测试此案例,如果没有可用的程序参数,则使用诊断消息终止。
答案 1 :(得分:-2)
您的主要问题:您没有为新字符串分配内存(string keyword = ""
)。
在C中,编译时未知的每个大小都必须在运行时动态分配。
此外,您永远不会检查可能导致程序崩溃的缺失参数。
请参阅下面的代码了解这两个修补程序
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: %s <word>\n", argv[0]);
return 1;
}
int length = strlen(argv[1]);
string keyword = malloc(length+1);
for(int i = 0, n = strlen(argv[1]); i < n; i++)
{
keyword[i] = toupper(argv[1][i]);
printf("%i-- printing letters\n", keyword[i]);
}
keyword[length]=0;
free(keyword);
}