CS50 第 4 周过滤器和 "void vs pointers"
CS50 week 4 filter and "void vs pointers"
我正在尝试使用 CS50 制作灰度滤镜。
首先 - 为什么我的代码无法正常工作,而我在 GitHub 上找到的与我的代码非常相似的代码却运行良好。
这是我的代码:
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
int i = 0, j = 0;
float rgbGray;
while (i < height)
{
while (j < width)
{
rgbGray = (image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed) / 3.00;
rgbGray = round(rgbGray);
image[i][j].rgbtBlue = rgbGray;
image[i][j].rgbtGreen = rgbGray;
image[i][j].rgbtRed = rgbGray;
j++;
}
i++;
}
return;
}
这是我在 GitHub
上找到的工作代码
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
float rgbGray;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++) {
rgbGray = round( (image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed)/ 3.00);
image[i][j].rgbtBlue = rgbGray;
image[i][j].rgbtGreen = rgbGray;
image[i][j].rgbtRed = rgbGray;
}
}
return;
}
作者:https://gist.github.com/ndiecodes
第二个问题是 - 为什么不需要指针。我的意思是在讲座中有信息,我们需要在我们想要更改元素值的情况下使用指针。此函数不返回任何值 - 它只是 VOID - 所以我很好奇为什么第二个代码可以正常工作
您的代码使用 while 循环,在循环后不会将 j
重置回零。因此,第一行之后的每一行都没有执行任何操作。
其次,这里没有 显式 指针,但是 C 数组被有效地传递,就好像(松散地说)它们是指向数据的指针,所以您对 image
影响调用者看到的数据。
Second question is - why there aren't pointers needed. I mean in lecture there is information, that we need to use pointers in cases where we want to change values of elements.
数组很奇怪。
除非它是 sizeof
或一元 &
运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 类型的“T
的 N 元素数组”将被转换(或“衰减”)为“指向 T
的指针”类型的表达式,表达式的值将是数组第一个元素的地址。
当你以数组表达式作为参数调用函数时,函数实际接收的是指向第一个元素的指针:
int arr[10];
foo( arr ); // equivalent to foo( &arr[0] );
...
void foo( int *a ) { ... }
在你的例子中,当你像这样调用 grayscale
时:
RGBTRIPLE image[rows][cols];
...
grayscale( rows, cols, image );
grayscale
实际收到的是 指针 指向 RGBTRIPLE
:
的 cols
元素数组
void grayscale( int height, int width, RGBTRIPLE (*image)[width] )
{
...
}
然而...
在函数参数声明的上下文中,任何类型为 T []
或 T [N]
的参数都将“调整”为类型 T *
,因此我可以 声明 foo
为
中的任何一个
void foo( int a[10] )
或
void foo( int a[] )
或
void foo( int *a )
并且所有内容的解释方式相同 - a
是 指向 int
的指针 ,而不是 int
的数组。这就是为什么您仍然可以将 grayscale
声明为
void grayscale( int height, int width, RGBTRIPLE image[height][width] )
数组下标是根据指针操作定义的。表达式 a[i]
被定义为 *(a + i)
- 给定起始地址 a
,偏移 i
个对象( 不是字节!)解决并取消引用结果:
a[0] == *(a + 0) == *a
a[1] == *(a + 1)
a[2] == *(a + 2)
等等
数组访问是为什么衰减规则首先存在。 C是从一种更早的语言B派生出来的(B派生自BCPL,BCPL派生自CPL,受Algol等的影响)。在 B 语言中,有一个指向数组第一个元素的显式指针。给定声明
auto vec[10];
你会在记忆中得到这个:
+---+
vec: | | ----------+
+---+ |
... |
+---+ |
| | vec[0] <--+
+---+
| | vec[1]
+---+
...
所以在 B 中 a[i]
== *(a + i)
的等价性是有意义的——你总是有一个指向第一个元素的显式指针。
当他在设计 C 时,Ritchie 想保留 B 的数组行为,但他不想为行为所需的显式指针预留 space - 他只想预留 space 用于数组元素本身。鉴于
int vec[10];
你得到
+---+
vec: | | vec[0]
+---+
| | vec[1]
+---+
...
所以他想出了衰减规则 - 任何时候编译器看到一个数组表达式不是 &
或 sizeof
(或 _Alignof
)的操作数,它用指向数组第一个元素的指针替换该表达式。
这就是为什么在将数组参数传递给 scanf
等函数时 不需要 需要使用 &
的原因,以及为什么不能return 来自函数的数组 - 所有得到 returned 的是指向数组第一个元素的指针,当函数 returns.
我正在尝试使用 CS50 制作灰度滤镜。
首先 - 为什么我的代码无法正常工作,而我在 GitHub 上找到的与我的代码非常相似的代码却运行良好。
这是我的代码:
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
int i = 0, j = 0;
float rgbGray;
while (i < height)
{
while (j < width)
{
rgbGray = (image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed) / 3.00;
rgbGray = round(rgbGray);
image[i][j].rgbtBlue = rgbGray;
image[i][j].rgbtGreen = rgbGray;
image[i][j].rgbtRed = rgbGray;
j++;
}
i++;
}
return;
}
这是我在 GitHub
上找到的工作代码void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
float rgbGray;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++) {
rgbGray = round( (image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed)/ 3.00);
image[i][j].rgbtBlue = rgbGray;
image[i][j].rgbtGreen = rgbGray;
image[i][j].rgbtRed = rgbGray;
}
}
return;
}
作者:https://gist.github.com/ndiecodes
第二个问题是 - 为什么不需要指针。我的意思是在讲座中有信息,我们需要在我们想要更改元素值的情况下使用指针。此函数不返回任何值 - 它只是 VOID - 所以我很好奇为什么第二个代码可以正常工作
您的代码使用 while 循环,在循环后不会将 j
重置回零。因此,第一行之后的每一行都没有执行任何操作。
其次,这里没有 显式 指针,但是 C 数组被有效地传递,就好像(松散地说)它们是指向数据的指针,所以您对 image
影响调用者看到的数据。
Second question is - why there aren't pointers needed. I mean in lecture there is information, that we need to use pointers in cases where we want to change values of elements.
数组很奇怪。
除非它是 sizeof
或一元 &
运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 类型的“T
的 N 元素数组”将被转换(或“衰减”)为“指向 T
的指针”类型的表达式,表达式的值将是数组第一个元素的地址。
当你以数组表达式作为参数调用函数时,函数实际接收的是指向第一个元素的指针:
int arr[10];
foo( arr ); // equivalent to foo( &arr[0] );
...
void foo( int *a ) { ... }
在你的例子中,当你像这样调用 grayscale
时:
RGBTRIPLE image[rows][cols];
...
grayscale( rows, cols, image );
grayscale
实际收到的是 指针 指向 RGBTRIPLE
:
cols
元素数组
void grayscale( int height, int width, RGBTRIPLE (*image)[width] )
{
...
}
然而...
在函数参数声明的上下文中,任何类型为 T []
或 T [N]
的参数都将“调整”为类型 T *
,因此我可以 声明 foo
为
void foo( int a[10] )
或
void foo( int a[] )
或
void foo( int *a )
并且所有内容的解释方式相同 - a
是 指向 int
的指针 ,而不是 int
的数组。这就是为什么您仍然可以将 grayscale
声明为
void grayscale( int height, int width, RGBTRIPLE image[height][width] )
数组下标是根据指针操作定义的。表达式 a[i]
被定义为 *(a + i)
- 给定起始地址 a
,偏移 i
个对象( 不是字节!)解决并取消引用结果:
a[0] == *(a + 0) == *a
a[1] == *(a + 1)
a[2] == *(a + 2)
等等
数组访问是为什么衰减规则首先存在。 C是从一种更早的语言B派生出来的(B派生自BCPL,BCPL派生自CPL,受Algol等的影响)。在 B 语言中,有一个指向数组第一个元素的显式指针。给定声明
auto vec[10];
你会在记忆中得到这个:
+---+
vec: | | ----------+
+---+ |
... |
+---+ |
| | vec[0] <--+
+---+
| | vec[1]
+---+
...
所以在 B 中 a[i]
== *(a + i)
的等价性是有意义的——你总是有一个指向第一个元素的显式指针。
当他在设计 C 时,Ritchie 想保留 B 的数组行为,但他不想为行为所需的显式指针预留 space - 他只想预留 space 用于数组元素本身。鉴于
int vec[10];
你得到
+---+
vec: | | vec[0]
+---+
| | vec[1]
+---+
...
所以他想出了衰减规则 - 任何时候编译器看到一个数组表达式不是 &
或 sizeof
(或 _Alignof
)的操作数,它用指向数组第一个元素的指针替换该表达式。
这就是为什么在将数组参数传递给 scanf
等函数时 不需要 需要使用 &
的原因,以及为什么不能return 来自函数的数组 - 所有得到 returned 的是指向数组第一个元素的指针,当函数 returns.