学习c有理解指针的困难

学习c有理解指针的困难,c,C,现在正在学习c,一位朋友给我发了这段代码,我不明白它的作用。对指针部分的解释会有所帮助。据我所知,它似乎是将arg的值复制到i字符的target中?指针是一个存储地址的变量。这个地址可以是 另一个变量的定义: void bar (char *arg, char *targ, int len) { int i; for (i = 0; i < len; i++) { *targ++ = *arg++; } } 或者,它可以是动态分配内存块的开始: int a = 1

现在正在学习c,一位朋友给我发了这段代码,我不明白它的作用。对指针部分的解释会有所帮助。据我所知,它似乎是将arg的值复制到i字符的target中?

指针是一个存储地址的变量。这个地址可以是 另一个变量的定义:

void
bar (char *arg, char *targ, int len)
{
  int i;
  for (i = 0; i < len; i++)
  {
    *targ++ = *arg++;
  }
}
或者,它可以是动态分配内存块的开始:

int a = 18;
int *pa = &a;
重要的是指针允许您访问 住址可以通过使用*-运算符取消对指针的引用来执行此操作:

int *p = malloc(sizeof *p);
int arr[] = { 1, 3, 5 };
int *p = arr;
对于这些例子来说,这似乎不是什么大不了的事,但事实上, 因为您可以向函数传递指针,然后这些函数可以交互 指针指向的内存,取决于内存块,甚至 修改它

指针也可以指向对象序列的开始,例如 阵列的开始:

int a = 18;
int *pa = &a;

*pa = 10;

printf("a=%d\n", a); // will print 10
注:p[0]为1,p[1]为3,p[2]为5。也可以更改 通过执行p[1]=-14;来获取值;。这也是解引用,但您也可以使用 *-接线员:

int *p = malloc(sizeof *p);
int arr[] = { 1, 3, 5 };
int *p = arr;
这就是您的代码片段所使用的内容。暂时忘记循环。看一看 在这一行:

p[1] = 12;
// is equivalent to
*(p + 1) = 12;
这可以改写为:

*targ++ = *arg++;
现在它正在做什么更清楚了。它复制第一个字符的值 由arg指向目标所指向的位置。之后两者 arg和targ将递增,以前进到 顺序1

因此,循环所做的是将arg指向的len对象复制到 塔格。这可用于将字符串复制到另一个字符数组中。但事实确实如此 不安全,因为不清楚是否复制了'\0'-终止字节 目前还不清楚缓冲区是否足够大,也就是说,是否比 伦恩。如果它们不是字符串而是字节序列,则此函数将 没事

在C语言中,字符串只是以“\0”结尾的字符序列。 因此,它们使用字符数组存储并传递给函数 作为char的指针,它指向字符串的开头。我们可以重写 以更安全的方式执行此功能,如下所示:

targ[0] = arg[0];
targ = targ + 1;  // or targ = &(targ[1])
arg = arg + 1;    // or arg = &(arg[1])
a用6初始化。初始化b时,编译器将使用 初始化的当前值,但后增量 运算符的副作用是将a的值增加1。什么时候 这完全是由规则定义的。什么 重要的是在初始化b时,使用了a的当前值
赋值后,a将有一个新值。

指针指向数据,通常包含数据的内存地址。指针是一个普通的“c”变量

使用指针时应用的运算符“*”告诉编译器在指针指示的位置访问数据

int a = 6;
int b = a++;
// a == 7, b == 6
应用于指针的运算符“++”,增加其值,使其指向上一个数据元素旁边的下一个数据元素。因此,对于'char*'指针,它将地址增加'1'以指向字符串中的下一个字符

在您的例子中,*targ++意味着:访问指针“targ”引用的数据,然后增加指针的值

int a = 6;
int b = a++;
// a == 7, b == 6

在上面的表达式中,程序获取由“arg”指向的字符,并将其分配到由“targ”引用的字符位置。然后它递增指针“arg”和“targ”的值

以下是您提供的函数,并对该函数进行了逐行解释。最后是为了使功能更加安全而进行的修改

此行声明函数的返回类型。类型“void”表示此函数不返回任何与函数相反的过程

*targ++ = *arg++;
{
此行声明函数名“bar”,然后列出三个参数“arg”、“targ”和“len”。这些参数的类型是'arg'是指向字符的指针,是在C中传递字符串的方式;'targ'也是指向字符的指针,也是在C中传递字符串的方式;“len”是一个整数

void
此符号“{”表示函数定义的主体如下

bar (char *arg, char *targ, int len)
此行声明'i'是'int'eger类型的变量,并且该变量在堆栈上为函数的持续时间保留了空间

*targ++ = *arg++;
{
此行使用“for”关键字声明重复循环。括号之间显示三个子部分:第一部分包含循环开始前的初始化,变量“i”设置为值0;第二部分包含计算以确定是否继续循环的表达式,在本例中为表达式“i”每次通过循环时都会检查
  int i;
这一行是执行函数有趣工作的地方 如上所述,对于列表0,1,2,3…中的每个“i”值,将执行一次for循环,len-1系列。请注意,循环在“i”的值为“len”时结束。参考上面的函数声明行,变量“arg”和“targ”是如何指向字符的指针的?这些行取消引用这些变量以访问指针位置

假设行为'*targ=*arg',则R值*arg将是'arg'指向的当前位置的内容,L值'*targ'将是'targ'指向的当前位置。如果字符“x”存储在“*arg”,则“x”将被复制到“*targ”,覆盖以前的内容

  {
指针后面的“++”符号不影响指针指向的字符,但由于“*”和“++”运算符的优先级,指针会递增。这一行可以改写为

    *targ++ = *arg++;
此行“}”关闭for循环的语句体

  for (i = 0; i < len; i++)
    *targ = *arg;
    arg++;
    targ++;
此符号“}”匹配并关闭函数定义的主体

  }
您应该始终检查函数的有效参数。您应该检查这些值是否超出其缓冲区。我在函数中添加了一些语句,使其更加健壮。如前所述,函数的行为类似于“memcpy”,不关心终止的“strings”;我添加了“endc”来检测字符串结束

}

有人会说不需要检查长度。简单函数也是如此,但复杂函数可能会表明这种习惯是有益的。

你是对的,这正是它所做的:-不,它将arg的值复制到len字符的target,而不是i字符。但我想这才是你真正的意思。欢迎来到stackoverflow。简单解释一下后增量运算符的副作用是如何在赋值发生后才应用的,以及*targ++=*arg++;与*targ=*arg相同;然后targ+=1;和arg+=1;。很好的解释。@DavidC.Rankin我添加了带有++副作用的部件。第二部分我在回答中已经谈到了。感谢您的反馈。与上面的评论相同,解释如何在计算表达式*targ和*arg并进行赋值后,将post增量作为副作用应用将很有帮助。