我在学习C方面遇到了一些问题,而且我真的没有其他地方可以提出建议.我来自一系列OOP语言,例如JavaScript和主要是Python,因此C是一个重大变化,我在尝试学习基础知识方面遇到了一些障碍.我最初是从Zed Shaw的"艰难学习C"开始的,但他并没有在书中教授任何东西.是的,他让你写了很多代码并改变了一些东西,但是我不知道为什么代码会工作,而这只会导致更复杂的例子.
我遇到的主要问题是变量和指针之间的区别(我认为它是非常独特的,直到我看到一些我将在下面发布的例子,这完全模糊了两者之间的界限).
例如,我理解声明和初始化一个int被调用的a和一个指针,p看起来像这样:
int a;
int *p;
a = 12;
p = &a;
Run Code Online (Sandbox Code Playgroud)
令我困惑的是当你声明看起来像指针的变量,但根本不是指针(或者它们是什么?).例如:
char *string = "This is a string";
printf("%s\n", string);
Run Code Online (Sandbox Code Playgroud)
什么string时候定义和初始化?它是指针吗?如果是的话,为什么不在printf函数中打印它时取消引用它?有很多像这样的例子让我很困惑.
我遇到的另一个例子没有任何意义:
int i;
scanf("%d", &i);
Run Code Online (Sandbox Code Playgroud)
i当&符号应该引用变量的内存中的位置而不是值时,这个函数如何更新整数的值?阵列和结构变得更加复杂,这是我停下来的地方,我决定要找一些建议.
老实说,我觉得很尴尬发布这样一个菜鸟问题,但每个人都从某个地方开始.这些基础知识是我知道在继续之前需要能够理解的东西,但是当我看到与我刚刚学到的内容相矛盾的代码示例时,我很难理解它.我知道这是一个非常普遍的问题,但我希望你们中的一些人能够解释这些基础知识,或者指出我可以更好地学习/理解这一点的方向.我遇到的大多数视频教程都过于笼统,与在线文本教程相同,他们告诉你如何做某事,但不解释它,这会导致一些严重的问题.
我会尝试和其他人稍微不同地解释一下.
考虑到你来自JavaScript和Python,我会在谈论指针时避免使用术语"引用".这是因为虽然它们相似但它们并不相同.
指针是存储地址的变量.就这么简单.指向int存储指针的指针int.
当您取消引用指针时,您告诉编译器要操作,而不是在地址上,而是在存储在该地址的内容上.
int *p;
int a = 7;
p = &a;
*p = 5;
Run Code Online (Sandbox Code Playgroud)
该*p = 5告诉编译器去到被存储在内部的地址p并存储该值5存在(如由于指针的整数p指向的整数).因此,无论我们在何处使用变量,我们都可以使用解引用指针代替变量.
你应该使用:
int *p;
p = 5;
Run Code Online (Sandbox Code Playgroud)
然后,您将为5指针分配(可能在内存中的任何位置)的地址(内存位置).如果您尝试使用不允许的内存位置,则程序可能会崩溃.
该&运营商需要一些变量的地址.它真的不关心它是什么,它甚至可以接受指针的地址.
int a;
int *p;
int **pp;
pp = &p;
p = &a;
Run Code Online (Sandbox Code Playgroud)
就是这样.
你的例子
字符串示例
char *string = "This is a string";
printf("%s\n", string);
Run Code Online (Sandbox Code Playgroud)
您感到困惑的原因是,在JavaScript和Python中,您可以将字符串视为可以适合变量.它不能!在C中,字符串是按顺序存储在存储器(字符数组)中的字符序列.这就是我们可以使用指针的原因.我们做的是让指针指向第一个字符,然后我们知道整个字符串的位置(因为它是顺序的).另外,在C中我们不存储字符串的大小.相反,字符串从指针开始,当我们遇到零字节'\0'或简单时结束0.
scanf示例
int i;
scanf("%d", &i);
Run Code Online (Sandbox Code Playgroud)
scanf给出地址的原因是i因为它会将通过控制台输入的整数放入其中的位置i.这种方式scanf实际上可以有多个返回值,这意味着:
int i, j;
scanf("%d%d", &i, &j);
Run Code Online (Sandbox Code Playgroud)
是可能的.由于scanf知道变量的地址,因此可以使用正确的值更新它们.