void
bar (char *arg, char *targ, int len)
{
int i;
for (i = 0; i < len; i++)
{
*targ++ = *arg++;
}
}
现在学习c,朋友给我发了这个片段,我无法理解它的作用。对指针部分的解释会很有帮助。根据我的理解,它似乎是将arg的值复制到tar中为我的字符?
答案 0 :(得分:4)
指针是存储地址的变量。该地址可以是地址 另一个变量:
int a = 18;
int *pa = &a;
或者它可以是动态分配的内存块的开始:
int *p = malloc(sizeof *p);
重要的是指针允许您访问后面的值
地址。您可以使用*
- 运算符:
int a = 18;
int *pa = &a;
*pa = 10;
printf("a=%d\n", a); // will print 10
对于这些例子,这可能看起来不是什么大问题,但它是, 因为您可以将指针传递给函数,然后这些函数可以进行交互 指针指向的内存,取决于内存块,甚至 修改它。
指针也可以指向对象序列的开始,例如指向 数组的开头:
int arr[] = { 1, 3, 5 };
int *p = arr;
注意p[0]
为1,p[1]
为3,p[2]
为5.也可以更改
做p[1] = -14;
的价值观。这也是解除引用,但你也可以使用
*
- 操作者:
p[1] = 12;
// is equivalent to
*(p + 1) = 12;
这就是你的代码片段所使用的内容。忘了一秒循环。看一看 在这一行:
*targ++ = *arg++;
这可以改写为:
targ[0] = arg[0];
targ = targ + 1; // or targ = &(targ[1])
arg = arg + 1; // or arg = &(arg[1])
现在它更清楚它在做什么。它复制第一个字符的值
arg
指向targ
指向的位置。在那之后
arg
和targ
会递增以前进到下一个元素
序列。 1
所以循环正在做的是复制len
指向的arg
个对象
targ
。这可以用于将字符串复制到另一个char
数组中。但它是
不安全,因为不清楚'\0'
- 终止字节是否被复制
目前尚不清楚缓冲区是否足够大(意味着大于
len
)。如果它们不是字符串而是字节序列,那么这个函数会
没关系。
在C中,字符串只是以'\0'
- 终止字节结尾的字符序列。
因此,它们使用char
数组存储并传递给函数
作为char
的指针,指向字符串的开头。我们可以改写
这个功能更加安全,如下所示:
int safe_copy_string(char *dest, char *source, size_t dest_size)
{
if(dest == NULL || source == NULL)
return 0;
if(dest_size == 0)
return 1; // no space to copy anything
// copying one element less than dest_size
// that last element if dest should be \0
for(size_t i = 0; i < dest_size - 1; ++i)
{
*dest++ = *source++;
if(*(source - 1) == '\0')
break; // copied sources's 0-terminating byte
}
dest[dest_size - 1] = 0; // making sure it is 0-terminated
return 1;
}
<强> Footenotes 强>
1 这里值得一提的是++
- 运算符。这是后增量
在指针的情况下,用于向操作数(对于整数)添加1的运算符
将指针前进1,使其指向下一个对象。
当你这样做时:
int a = 6;
int b = a++;
// a == 7, b == 6
a
初始化为6.初始化b
时,编译器将使用。{
初始化的当前值a
,但后增量
运算符的副作用是它会将a
的值增加1
这恰好是由sequence points的规则定义的。什么
重要的是,在b
的初始化中,使用了a
的当前值
并且在作业a
之后将有一个新值。
答案 1 :(得分:0)
指针指向数据,通常包含数据的内存地址。指针是正常的&#39; c&#39;变量。
运营商&#39; *&#39;当使用指针时,应用时,告诉编译器在指针表示的位置访问数据。
运算符&#39; ++&#39;,应用于指针,增加其值,使其指向与前一个数据元素相邻的下一个数据元素。所以,对于&#39; char *&#39;指针,它通过&#39; 1&#39;增加地址。指向字符串中的下一个字符。
在您的情况下,$BaseVM
表示:访问指针引用的数据&#39; targ&#39;然后递增指针的值。
*targ++
在上面的表达式中,程序采用了指向&#39; arg&#39;并将其分配给&#39; targ&#39;引用的char位置。然后它增加指针的值&#39; arg&#39;和&#39; targ&#39;。
答案 2 :(得分:0)
这是您提供的功能,以功能的逐行说明进行分解。最后是修改,使功能稍微安全。
此行声明函数的返回类型。类型'void'表示此函数不返回任何内容(与函数相对的过程)。
void
此行声明函数的名称'bar',然后显示三个参数的列表,'arg','targ'和'len'。这些参数的类型是'arg'是指向字符的指针,是你在C中传递字符串的方式; 'targ'也是一个指向字符的指针,再次是你在C中传递字符串的方式; 'len'是一个int(eger)。
bar (char *arg, char *targ, int len)
此符号“{”表示函数定义的主体如下。
{
该行声明'i'是'int'(eger)类型的变量,并且该变量在函数持续时间内在堆栈上保留空间。
int i;
此行使用'for'关键字声明重复循环。在括号之间出现三个子部分:第一部分包含循环开始之前的初始化,变量'i'设置为值0;第二部分包含一个表达式,该表达式被计算以确定是否继续循环,在这种情况下表达式'i&lt;每次遍历循环都会检查len',因此当i的值大于或等于'len'的值时,循环终止;第三部分包含一个在每个循环传递结束时执行的表达式。
for (i = 0; i < len; i++)
这一行'{'打开for循环的语句体,
{
这一行是执行函数的有趣工作的地方。如上所述,for循环将对列表中的每个'i'值(0,1,2,3,...,len-1)执行一次,顺序执行。注意,当'i'具有值'len'时,循环结束。请参阅上面的函数声明行,变量'arg'和'targ'是如何指向字符的?这些行取消引用这些变量以访问指针位置。
假设该行是'* targ = * arg',那么R值* arg将是'arg'所指向的当前位置的内容,而L值'* targ'将是当前的位置由'targ'指出。如果字符'x'存储在'* arg'中,则'x'将被复制到'* targ',覆盖之前的内容。
*targ++ = *arg++;
指针之后的'++'符号不会影响指针指向的字符,但会增加指针(由于'*'和'++'运算符的优先级)。这一行可以改写为,
*targ = *arg;
arg++;
targ++;
这一行'}'关闭for循环的语句体
}
此符号'}'匹配并关闭函数定义的主体。
}
您应该始终检查函数的有效参数。您应该检查值是否超出缓冲区。我在函数中添加了一些语句,使其更加健壮。如上所述,该函数的行为类似于'memcpy',并不关心终止的'字符串';我添加了'endc'来检测字符串结束。
char* //return the destination, for further processing, e.g. strlen()
bar (char *arg, char *targ, int len)
{
int ndx; //try searching for 'i' in a big source file sometime...
char endc; //temporary to detect null character, more like 'strncpy'
if( (!arg) || (!targ) || (len<1) ) return targ;
for (ndx = 0; ndx < len; ndx++)
{
endc = *targ++ = *arg++;
if( !endc ) break; //comment this out for 'memcpy' behavior
}
}
有人会说不需要检查长度。对于简单的函数来说也是如此,但复杂的函数可能会发现这种习惯是有益的。