gpt4 book ai didi

c - C编程命令行参数问题

转载 作者:行者123 更新时间:2023-11-30 20:19:01 25 4
gpt4 key购买 nike

我被要求检查命令行参数
不使用strcmp和整个string.h
不使用任何[ ],即没有数组操作而只有指针。

如何检查两个字符串之间的相等性?
我尝试了("String" == *(argv + 1)),但是它不起作用,*(argv + 1)给了我确切的字符串,但是地址不同。
另一方面,我无法逐字符检查字符,因为它是char *而不是char []
agrv的类型是char **而不是char *[]

#include <stdio.h>
int main(int argc, char ** argv) {
printf("%s", *(argv + 1));
return 0;
} // Works in the terminal

#include <stdio.h>
int main(int argc) {
char ** argv = {"String1", "String2"};
printf("%s", *(argv + 1));
return 0;
} // Does not work in IDE, not really understand how char ** works

最佳答案

比较不带[]的字符串

当您的讲师问您不要使用strcmp()中的string.h时,这并不意味着您被禁止自己写!

为此,您必须考虑strcmp()的作用。在C语言中,字符串基本上是用0终止的数组,这意味着数组中的最后一个元素是0。因此,如果遍历数组并找到这样的元素,就知道已经到了尽头。

根据您的问题,我假设您知道[]运算符对数组的访问是如何工作的。因此,我将向您展示如何使用[]运算符比较两个字符串。

int my_strcmp(const char * str1, const char * str2)
{
int idx = 0;

while ( (str1[idx] == str2[idx])
&& (str1[idx] != 0)
&& (str2[idx] != 0)) {
++idx;
}

return str2[idx] - str1[idx];
}


因此,我们开始比较两个字符串的前几个元素。

(str1[idx] == str2[idx])检查元素是否相同。
(str1[idx] != 0)检查字符串1是否终止,而 (str1[idx] != 0)检查字符串2是否终止。因此,当字符串相等且未结束时,我们将停留在循环中。

当任何一个条件失败时,我们将返回当前元素的差值-如果两个字符串相等,则 strcmp()返回 0-我们在上述函数中具有相同的行为。

下一步是将 []访问转换为指针访问。在这里,您有多种可能。


您可以增加字符串指针( ++str1;)并比较取消引用它们( *str1)。

int my_strcmp(const char * str1, const char * str2)
{
while ( (*str1 == *str2)
&& (*str1 != 0)
&& (*str2 != 0)) {
++str1;
++str2;
}

return *str2 - *str1;
}

您可以使用添加到字符串的基本指针的索引( ++idx;)并取消引用总和( *(str1 + idx))。

int my_strcmp(const char * str1, const char * str2)
{
int idx = 0;

while ( (*(str1 + idx) == *(str2 + idx))
&& (*(str1 + idx) != 0)
&& (*(str2 + idx) != 0)) {
++idx;
}

return *(str2 + idx) - *(str1 + idx);
}



因此,您只需在主要功能中使用此功能。

int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "missing parameter\n");
return 1;
} else {
if (my_strcmp(*(argv + 1), "my secret compare string") == 0) {
printf("argument is equal\n");
} else {
printf("argument is unequal\n");
}
return 0;
}
}


指针到指针

我也从您的问题中看到,您对 **不熟悉。

当我们要存储字符时,我们声明一个变量,例如

char v = 'x';


在这种情况下,编译器会在RAM中保留一些空间,例如在地址 1003上。每次访问变量 v时,都会读取或写入地址 1003的值。

addr.  value
+--------+
1002 | 'x' |
+--------+


如果您声明此

char * pv = "text2";


RAM中存储了多个内容。首先是字符串本身-由字符串的5个字符和一个终止的 0组成-例如在地址 1100上。另外,还存储了指向该数组的指针,例如在地址 3004上。在地址 3004上存储值 1100-字符串的地址。

addr.  value
+--------+
1100 | 't' |<--------+
+--------+ |
1101 | 'e' | |
+--------+ |
1102 | 'x' | |
+--------+ |
1103 | 't' | |
+--------+ |
1104 | '2' | |
+--------+ |
1105 | 0 | |
+--------+ |
. |
. |
. |
+--------+ |
3004 | 1100 |---------+
+--------+


最后,您将获得一个此类指针的数组。为了解决这个问题,您存储了一个指向指针的指针。

char ** ppv = &pv;


这里是存储的字符串本身(在地址 100011001300上),指向这些字符串的指针(在地址 300030043008上)以及作为最后一个元素的指针地址 4192上的指针数组的开始。

addr.  value
+--------+
1000 | 't' |<------------+
+--------+ |
1001 | 'e' | |
+--------+ |
1002 | 'x' | |
+--------+ |
1003 | 't' | |
+--------+ |
1004 | '3' | |
+--------+ |
1005 | 0 | |
+--------+ |
. |
. |
. |
+--------+
1100 | 't' |<--------+ |
+--------+ | |
1101 | 'e' | | |
+--------+ | |
1102 | 'x' | | |
+--------+ | |
1103 | 't' | | |
+--------+ | |
1104 | '2' | | |
+--------+ | |
1105 | 0 | | |
+--------+ | |
. | |
. | |
. | |
+--------+ | |
1300 | 't' |<----+ | |
+--------+ | | |
1301 | 'e' | | | |
+--------+ | | |
1302 | 'x' | | | |
+--------+ | | |
1303 | 't' | | | |
+--------+ | | |
1304 | '1' | | | |
+--------+ | | |
1305 | 0 | | | |
+--------+ | | |
. | | |
. | | |
. | | |
+--------+ | | |
3000 | 1300 |-----+ | | <------+
+--------+ | | |
3004 | 1100 |---------+ | |
+--------+ | |
3008 | 1000 |-------------+ |
+--------+ |
. |
. |
. |
+--------+ |
4192 | 3000 |----------------------+
+--------+


因此,当操作系统创建您的进程时,它将所有程序参数存储在ram中,并存储这些字符串的指针列表。 argv是此列表的指针。

声明一个指针数组

要声明一个指针数组,您必须使用以下语法:

const char * arr[] = { "HeLLo", "World!" };


但是,为什么您的尝试 char ** arr = { "HeLLo", "World" };无法成功?您正在声明一个名为 arr的变量,该变量是指向 char的指针的指针。因此,基本上,您要求编译器为指针分配内存。为了使事情变得简单,我们将讨论一种具有32位寄存器宽度和32位地址空间的机器。在这种情况下,指针的大小为4个字节。

此变量 arr应指向chars的指针列表,但您不指示编译器分配该列表。那就是 char ** x = ...;char * x[] = ...;之间的区别。在后一种情况下,您指示编译器还为列表分配内存,而不仅仅是为指向该列表的指针分配内存。

当您的代码中包含以下(错误)行时

char ** x = { "HeLLo", "World" };
printf("%s\n", x);


编译器可能会引发以下警告/错误:

$ gcc -std=c99 --pedantic -Wall -Wextra file.c -o mybin
file.c: In function ‘f’:
file.c:21:16: warning: initialization of ‘char **’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types]
char ** x = { "HeLLo", "World" };
^~~~~~~
file.c:21:16: note: (near initialization for ‘x’)
file.c:21:25: warning: excess elements in scalar initializer
char ** x = { "HeLLo", "World" };
^~~~~~~
file.c:21:25: note: (near initialization for ‘x’)


我认为警告/错误说明了一切。

如第一个警告所述,您正在使用 x值初始化 "HeLLo",该值是指向字符串的指针。第二个警告告诉您,由于未使用 "World",您有一些无效代码。

当您尝试在行中打印 x

printf("%s\n", x);


您会遇到某种程度的C语言缺乏的情况,因为在这里它不是类型安全的。格式表达式 %s需要类型 char *作为参数。 xchar **类型。您在这里看不到的内容已完成转换。 x的值不会更改,但会使用不同的语义进行解释。之所以可行,是因为您一开始分配的错误。

argc和argv

按照惯例, argc告诉您参数的数量,可以在 argv中找到。

int main(int argc, char **argv)
{
for (i = 0; i < argc; ++i) {
printf("argument %d is '%s'\n", i, argv[i]);
}
return 0;
}


您要知道的是,第一个元素(索引 0)是二进制文件的名称,其中可能包含指向二进制文件的某些路径。命令行中的第一个参数的索引为 1,第二个命令行参数的索引为 2,依此类推...

关于c - C编程命令行参数问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52171674/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com