C基础-变量和指针有问题

C基础-变量和指针有问题,c,pointers,C,Pointers,我在学习C时遇到了一些问题,我真的没有其他地方可以寻求建议。我来自一系列OOP语言,比如JavaScript,主要是Python,所以C是一个重大的变化,我在学习基础知识时遇到了不少困难。我最初是从Zed Shaw的“用艰苦的方式学习C”开始的,但他并没有在书中教授任何东西。是的,他让你写了很多代码,修改了很多东西,但我不知道为什么代码会工作,这只是导致了更多的混乱,因为这些例子越来越复杂 我遇到的主要问题是变量和指针之间的差异(我认为这是非常明显的,直到我在下面发布了一些示例,它们完全模糊了两

我在学习C时遇到了一些问题,我真的没有其他地方可以寻求建议。我来自一系列OOP语言,比如JavaScript,主要是Python,所以C是一个重大的变化,我在学习基础知识时遇到了不少困难。我最初是从Zed Shaw的“用艰苦的方式学习C”开始的,但他并没有在书中教授任何东西。是的,他让你写了很多代码,修改了很多东西,但我不知道为什么代码会工作,这只是导致了更多的混乱,因为这些例子越来越复杂

我遇到的主要问题是变量和指针之间的差异(我认为这是非常明显的,直到我在下面发布了一些示例,它们完全模糊了两者之间的界限)

例如,我知道声明和初始化名为
a
int
和指针
p
如下所示:

int a;
int *p;

a = 12;
p = &a;
// NOTE: not actual scanf implementation
void scanf(char* format, int * input) {
    *input = get_number(); // store value in variable
}
让我困惑的是,当您声明的变量看起来像指针,但实际上根本不是指针(或者是指针?)。例如:

char *string = "This is a string";
printf("%s\n", string);
char *string = “This is a string”;
printf(“%s\n”, string);
定义和初始化字符串时,它是什么?是指针吗?如果是,为什么不在
printf
函数中打印时取消引用它呢?有很多这样的例子让我困惑

我遇到的另一个毫无意义的例子:

int i;
scanf("%d", &i);
当符号应该引用变量在内存中的位置而不是值时,该函数如何更新整数
i
?数组和结构变得更加复杂,这就是我停下来决定需要寻求一些建议的地方


我真的觉得很尴尬发布这样一个noob问题,但每个人都从某个地方开始。我知道,在继续之前,我需要理解这些基本原理,但当我看到与我刚才所学内容相矛盾的代码示例时,我很难理解这些基本原理。我知道这是一个非常普遍的问题,但我希望你们中的一些人能够解释这些基本知识,或者为我指出一个我可以更好地学习/理解这一点的方向。我遇到的大多数视频教程都过于笼统,与在线文本教程相同,它们告诉你如何做某事,但没有解释,这会导致一些严重的问题

定义和初始化字符串时,字符串是什么?是指针吗?如果是,为什么不在printf函数中打印时取消引用它呢

这是一个指针。它直接指向字符串中的第一个字符。您不必取消引用它,因为
printf
将接受
char
指针。。并打印所有内容,直到找到空终止符(自动为您添加)

当符号应该引用变量在内存中的位置而不是值时,该函数如何更新整数i的值

因为
&i
使参数作为
int*
传入。因此,函数将取消引用并添加。。有点像这样:

int a;
int *p;

a = 12;
p = &a;
// NOTE: not actual scanf implementation
void scanf(char* format, int * input) {
    *input = get_number(); // store value in variable
}

读一些关于指针的基础知识怎么样

我将回答你的以下问题:

让我困惑的是,当您声明的变量看起来像指针,但实际上根本不是指针(或者是指针?)。例如:

char *string = "This is a string";
printf("%s\n", string);
char *string = “This is a string”;
printf(“%s\n”, string);
是的,他们是!它是一个字符指针

当符号应该引用变量在内存中的位置而不是值时,该函数如何更新整数
i


这取决于函数签名。如果你看看
scanf
接受什么作为参数列表,你就会明白。

我会回答你的具体问题,关于
printf
为什么没有传递一个去引用指针,以及
scanf
为什么传递一个地址,希望这能让一些事情更清楚


首先,按照惯例,C样式字符串是内存中的字符数组,由
\0
字符(称为NUL终止符)终止。跟踪C样式字符串的方法是保持指向字符串第一个字符的指针

当调用
printf(“%s\n”,some_str)
时,其中
some_str
类型为
char*
,则
printf
所做的是打印
some_str
指向的字符,然后打印它后面的字符(在内存中,通过简单地增加指针
some_str
定位),然后打印后面的字符,直到找到
\0
,然后停止打印

其他C风格的字符串操作函数也使用相同的过程,如
strcpy
strlen

这样做的一个原因是字符串往往具有不同的长度,因此需要不同的内存量,但不方便使用大小可变的数据类型。因此,我们对内存中字符串的格式有一个约定(本质上是
\0
终止符约定),我们只需用
字符*
指向字符串

如果您取消引用一个
字符*
,您将得到一个字符,而不是预期的字符串,因此请注意这一点


为什么
scanf(“%d”和&i)
将地址传递给
int
,而不是
int
本身

原因是在C语言中,函数参数是按值传递的,这意味着当你把某个东西传递给函数时,它的一个副本会被复制并传递给函数,而不管函数对副本做了什么,原始的都会保持原样。这意味着什么

首先,如果你有一个函数,比如:

void add_two(int i) {
  i = i + 2;
}
void really_add_two(int *i) {
  *i = *i + 2;
}
如果调用:
inti=3;加二(i)
,则
i
的值不会更改,因为
添加两个int i;
scanf("%d", &i);
int i, j;
scanf("%d%d", &i, &j);
int a;
+-----+
| int | 
+-----+
      +-----+
&a -> | int | 
      +-----+
int *p;
     +---------+
p -> |   int   |
     +---------+
p = &a;
int i;
scanf( "%d", &i );
int foo(int n) { return 11; }

int j = 10;
int i = foo(j);
int foo(int *p) { *p = 12; return 11; }

int j = 10;
int i = foo(&j);
    char *string = "This is a string";
    printf("%s\n", string);
    int i;
    scanf("%d", &i);
void swap( int a, int b ) { int tmp = a; a = b; b = tmp; return; }
...
int x = 0, y = 1;
printf( "before swap: x = %d, y = %d\n", x, y );
swap( x, y );
printf( " after swap: x = %d, y = %d\n", x, y );
void swap( int *a, int *b ) { int tmp = *a; *a = *b; *b = tmp; return; }
...
int x = 0, y = 1;
printf( "before swap: x = %d, y = %d\n", x, y );
swap( &x, &y );
printf( " after swap: x = %d, y = %d\n", x, y );