对 strcmp 感到困惑
Baffled by strcmp
我有一个非常简单的函数可以将表示位串的 3 个字符的字符串转换为十进制数:
int bin3_to_dec(char *bin) {
int result;
result=0;
printf("string: %s\n", bin);
printf("c0: %c\n", bin[0]);
printf("c1: %c\n", bin[1]);
printf("c2: %c\n", bin[2]);
if ((strcmp(&bin[0], "1") == 0))
result += 4;
if ((strcmp(&bin[1], "1") == 0))
result += 2;
if ((strcmp(&bin[2], "1") == 0))
result += 1;
printf("result: %d\n", result);
return result;
}
当我 运行 程序并为该函数提供字符串 111
时,它应该计算 7。相反,它输出:
string: 111
c0: 1
c1: 1
c2: 1
result: 1
为什么计算不正确?为什么只有第三个条件成功通过?
&bin[0] 实际上是一个指向字符数组的指针,从第 0 个索引开始,即 111。因此,您的第一次比较失败了。第二个也是如此。但是在你的第三次比较中, &bin[2] 是一个指向字符数组的指针,从第二个索引开始,它是 1,因此它将结果加 1。所以为了让你的代码工作:
you can check if(bin[0] == '1')
// 这里比较 bin[0] 处的字符,它等于 1,所以这里的条件得到满足。
if (bin[0] == '1') result += 4;
if (bin[1] == '1') result += 2;
if (bin[2] == '1') result += 1;
请注意 &bin[0] 与 bin
相同
bin[0]为第一个元素
&bin[0] 是指向第一个元素的指针,就像 bin
C 在遇到空值(即 \0)之前不会检测字符串的结尾。当您将“111”传递给您的函数时,您实际上传递了一个指向如下所示的内存块的指针:“111[=12=]”。因此,当您将 bin[0] 的地址传递给 strcmp() 时,strcmp 将对完整字符串“111”进行操作。当您将 bin[1] 的地址传递给 strcmp() 时,strcmp 对字符串“11”进行操作。只有当您将 bin[2] 的地址传递给 strcmp() 时,您才会得到预期的行为,因为在这种情况下,内存中的下一个字符为空。
您是否尝试过将 &bin[1]
(例如)打印为字符串而不是单个字符?因为这就是 strcmp()
看到他们的方式。
在你这样做时,strcmp(&bin[0], "1")
显然总是非零的,因为 &bin[0]
是完整的输入字符串并且(在我们的示例中)"111"
根本不像 "1"
。字符串 运行 直到空终止符。
您可以使用直接字符比较 (bin[0] == '1'
),将字符复制到它自己的以 null 结尾的字符串,或者(破坏性地)从右到左工作并插入空字符 ('[=17 =]'
) 在您感兴趣的字符之后。但是您不能将字符串的中间部分作为单个字符进行比较。
您的字符串 bin
等于“111”实际上由四个字符组成 - 即“1”、“1”、“1”、“\0”,其中第 4 个字符的值为零,终止(即结束)字符串。
所以 &bin[0]
是字符串 "111"
和&bin[1]
是字符串"11"
和&bin[2]
是字符串"1"
那么您的代码实际执行的操作与:
if ((strcmp("111", "1") == 0))
result += 4;
if ((strcmp("11", "1") == 0))
result += 2;
if ((strcmp("1", "1") == 0))
result += 1;
只有最后一次比较结果为真,所以 result
变成 1
正如其他人所提到的,您混淆了这些字符串。这三个都是字符串,但是 java 中的字符串是一个字符数组。因此,当您使用 &bin[0] 表示字符串“1”时,您实际上是在比较“111”。为什么?指向字符数组的指针构成一个字符串,该数组中的字符从指针显示的位置开始,一直持续到结尾。
因此,当您指向第一个字母时,您会得到“111”,当您指向第二个字母时,您会得到“11”,当您指向最后一个字符时,您会得到“1”,这就是为什么您的总和是1. 你可以尝试将字符串“1111”作为参数传递,你可以看到你的结果是 0 而不是 1.
您的代码似乎对 strcmp()
的函数调用感到困惑,这不是必需的,并且对于字符串文字 "1"
和之间的任何比较始终 return 非零代码中指向的任何 "sub-string"(&bin[0]
、&bin[1]
),除了 one-printable-member-string &bin[2]
,如果还有 "1"
。让我们来看看吧。
正如您在 函数原型 中正确编写的那样,指向 字符数组 第一个元素的指针是 通过值 传递给您的 调用的函数 并复制为它的参数。这是 "mechanism" 用于由指向的数组填充的内存部分,如果其 "upper bound" 已知,则由 调用的函数 可见。
有两种方法可以知道其上限:
- 将
char
数组大小作为附加参数传递给函数,或
- 在调用函数中以空值终止
char
数组,因此被调用函数可以将其解释为字符串,这是你的选择。 调用的函数 可以使用 strlen()
来确定字符串长度(大小),或者单步执行它,递增计数器,直到到达空字符,然后从中读取大小柜台.
如果 调用函数 已经收到数组作为 '0'
和 '1'
字符的空终止字符串,第二个看起来更实用。
根据 被调用函数 的 return 数据类型的存储容量允许最多允许的字符数(在本例中为 int
) 阐明了问题并简化了代码。 调用函数 应防止溢出。
调用的函数 应该只将每个数组成员的 ASCII 值与 '1'
进行比较,如果相等则进行转换。
为此 strcmp
不是必需的。
请参阅此演示代码中的注释,基于您的 post:
#include <stdio.h>
#include <string.h>
#define BPB 8 //bits per byte
int bin_to_dec(char *bin) //called function
{
int result=0;
int l = (int)strlen(bin);
for (int i = 0; i < l; i++){
printf("c%d: %c\n", i, bin[i]);
if(bin[i] == '1') //compare value of the i-th element
result += 1<<(l - i - 1); //convert to power-of-two and add to the result
}
return result;
}
int main(int argc, char *argv[]) //calling function
{
size_t siz = BPB*sizeof (int); //size for each char to represent one bit
char s[siz + 1]; //characters, each representing one bit + terminating '[=10=]'
if((argc < 2)||(argc > 2)) //fail-safe check for correct count of arguments
return 1;
size_t len = strlen(argv[1]) ; //get length of the input string
if ( len > siz ) //check against too long input which would cause overflow
return 2;
strncpy(s, argv[1], len);
s[len] = '[=10=]'; //appending the terminating null-character
for(int i = 0; i < (int)len; i++)
if((s[i] < '0')||(s[i] > '1')) //fool-proof check against 'off-limit' input
return 3;
printf("decimal: %d\n", bin_to_dec(s));
return 0;
}
我有一个非常简单的函数可以将表示位串的 3 个字符的字符串转换为十进制数:
int bin3_to_dec(char *bin) {
int result;
result=0;
printf("string: %s\n", bin);
printf("c0: %c\n", bin[0]);
printf("c1: %c\n", bin[1]);
printf("c2: %c\n", bin[2]);
if ((strcmp(&bin[0], "1") == 0))
result += 4;
if ((strcmp(&bin[1], "1") == 0))
result += 2;
if ((strcmp(&bin[2], "1") == 0))
result += 1;
printf("result: %d\n", result);
return result;
}
当我 运行 程序并为该函数提供字符串 111
时,它应该计算 7。相反,它输出:
string: 111
c0: 1
c1: 1
c2: 1
result: 1
为什么计算不正确?为什么只有第三个条件成功通过?
&bin[0] 实际上是一个指向字符数组的指针,从第 0 个索引开始,即 111。因此,您的第一次比较失败了。第二个也是如此。但是在你的第三次比较中, &bin[2] 是一个指向字符数组的指针,从第二个索引开始,它是 1,因此它将结果加 1。所以为了让你的代码工作:
you can check if(bin[0] == '1')
// 这里比较 bin[0] 处的字符,它等于 1,所以这里的条件得到满足。
if (bin[0] == '1') result += 4;
if (bin[1] == '1') result += 2;
if (bin[2] == '1') result += 1;
请注意 &bin[0] 与 bin
相同bin[0]为第一个元素
&bin[0] 是指向第一个元素的指针,就像 bin
C 在遇到空值(即 \0)之前不会检测字符串的结尾。当您将“111”传递给您的函数时,您实际上传递了一个指向如下所示的内存块的指针:“111[=12=]”。因此,当您将 bin[0] 的地址传递给 strcmp() 时,strcmp 将对完整字符串“111”进行操作。当您将 bin[1] 的地址传递给 strcmp() 时,strcmp 对字符串“11”进行操作。只有当您将 bin[2] 的地址传递给 strcmp() 时,您才会得到预期的行为,因为在这种情况下,内存中的下一个字符为空。
您是否尝试过将 &bin[1]
(例如)打印为字符串而不是单个字符?因为这就是 strcmp()
看到他们的方式。
在你这样做时,strcmp(&bin[0], "1")
显然总是非零的,因为 &bin[0]
是完整的输入字符串并且(在我们的示例中)"111"
根本不像 "1"
。字符串 运行 直到空终止符。
您可以使用直接字符比较 (bin[0] == '1'
),将字符复制到它自己的以 null 结尾的字符串,或者(破坏性地)从右到左工作并插入空字符 ('[=17 =]'
) 在您感兴趣的字符之后。但是您不能将字符串的中间部分作为单个字符进行比较。
您的字符串 bin
等于“111”实际上由四个字符组成 - 即“1”、“1”、“1”、“\0”,其中第 4 个字符的值为零,终止(即结束)字符串。
所以 &bin[0]
是字符串 "111"
和&bin[1]
是字符串"11"
和&bin[2]
是字符串"1"
那么您的代码实际执行的操作与:
if ((strcmp("111", "1") == 0))
result += 4;
if ((strcmp("11", "1") == 0))
result += 2;
if ((strcmp("1", "1") == 0))
result += 1;
只有最后一次比较结果为真,所以 result
变成 1
正如其他人所提到的,您混淆了这些字符串。这三个都是字符串,但是 java 中的字符串是一个字符数组。因此,当您使用 &bin[0] 表示字符串“1”时,您实际上是在比较“111”。为什么?指向字符数组的指针构成一个字符串,该数组中的字符从指针显示的位置开始,一直持续到结尾。
因此,当您指向第一个字母时,您会得到“111”,当您指向第二个字母时,您会得到“11”,当您指向最后一个字符时,您会得到“1”,这就是为什么您的总和是1. 你可以尝试将字符串“1111”作为参数传递,你可以看到你的结果是 0 而不是 1.
您的代码似乎对 strcmp()
的函数调用感到困惑,这不是必需的,并且对于字符串文字 "1"
和之间的任何比较始终 return 非零代码中指向的任何 "sub-string"(&bin[0]
、&bin[1]
),除了 one-printable-member-string &bin[2]
,如果还有 "1"
。让我们来看看吧。
正如您在 函数原型 中正确编写的那样,指向 字符数组 第一个元素的指针是 通过值 传递给您的 调用的函数 并复制为它的参数。这是 "mechanism" 用于由指向的数组填充的内存部分,如果其 "upper bound" 已知,则由 调用的函数 可见。
有两种方法可以知道其上限:
- 将
char
数组大小作为附加参数传递给函数,或 - 在调用函数中以空值终止
char
数组,因此被调用函数可以将其解释为字符串,这是你的选择。 调用的函数 可以使用strlen()
来确定字符串长度(大小),或者单步执行它,递增计数器,直到到达空字符,然后从中读取大小柜台.
如果 调用函数 已经收到数组作为 '0'
和 '1'
字符的空终止字符串,第二个看起来更实用。
根据 被调用函数 的 return 数据类型的存储容量允许最多允许的字符数(在本例中为 int
) 阐明了问题并简化了代码。 调用函数 应防止溢出。
调用的函数 应该只将每个数组成员的 ASCII 值与 '1'
进行比较,如果相等则进行转换。
为此 strcmp
不是必需的。
请参阅此演示代码中的注释,基于您的 post:
#include <stdio.h>
#include <string.h>
#define BPB 8 //bits per byte
int bin_to_dec(char *bin) //called function
{
int result=0;
int l = (int)strlen(bin);
for (int i = 0; i < l; i++){
printf("c%d: %c\n", i, bin[i]);
if(bin[i] == '1') //compare value of the i-th element
result += 1<<(l - i - 1); //convert to power-of-two and add to the result
}
return result;
}
int main(int argc, char *argv[]) //calling function
{
size_t siz = BPB*sizeof (int); //size for each char to represent one bit
char s[siz + 1]; //characters, each representing one bit + terminating '[=10=]'
if((argc < 2)||(argc > 2)) //fail-safe check for correct count of arguments
return 1;
size_t len = strlen(argv[1]) ; //get length of the input string
if ( len > siz ) //check against too long input which would cause overflow
return 2;
strncpy(s, argv[1], len);
s[len] = '[=10=]'; //appending the terminating null-character
for(int i = 0; i < (int)len; i++)
if((s[i] < '0')||(s[i] > '1')) //fool-proof check against 'off-limit' input
return 3;
printf("decimal: %d\n", bin_to_dec(s));
return 0;
}