假设我的指针看起来像:
char *tmp = calloc(1, 500);
然后我将值签名到指针:
char *token = "star";
for(int cur = 0, cur < 500,cur += 50){
strncpy(&tmp[cur], token, 50);//each 50 units will get a value
}
现在我有一个存储了多个值的指针。我应该怎样逐一打印出这个价值?
printf("--- %s\n", tmp); // this seems can only print the first one
我不知道如何跳转或读取下一个值,并保持读数直到打印整个指针。
答案 0 :(得分:2)
由于您使用(更正后的代码)将以null结尾的值复制到数组中:
for (int cur = 0; cur < 500; cur += 50)
strncpy(&tmp[cur], token, 50);
您可以使用以下方式打印值:
for (int cur = 0; cur < 500; cur += 50)
printf("--- %s\n", &tmp[cur]);
答案 1 :(得分:1)
for(int cur = 0, cur < 500,cur += 50){
这是错误的。逗号,
可能应该是分号;
,并且您无意中错误地使用了comma operator
现在我有一个存储了多个值的指针
请定义合适的类型。我没有看到指针中存储了几个“值”。
但是,您可以看到指针指向(指向)500 char
- s的数组。然后%s
printf
中出现%c
错误(您可能会使用gcc -Wall -Wextra -g
)。
建议:
花几天时间阅读一些优秀的C编程书。在学习C(这是一种困难的编程语言)之前,我甚至建议花几周时间阅读SICP(编程的优秀介绍,不使用C)和练习。
指定(在纸面上,用英语或您的母语),尽可能准确地说明您的代码应该做什么。
编译所有警告和调试信息,例如gdb
与GCC
抛弃你的代码,完全重写它(直到你没有得到任何警告),使用rubber duck debugging;了解如何debug small programs
在电路板上绘制你的记忆图片(带箭头指针和位置框)
使用调试器,例如struct
逐步运行代码并查询程序的状态,从而准确了解流程中发生的情况。
学习 - 获取灵感 - 一些现有 free software的源代码(例如github)
我应该怎样逐一打印出这个值?
首先,您需要了解并定义所涉及的types。也许你想要数组(什么类型?)或struct yourstruct {
char name[50];
};
- s(有哪些字段和类型),可能以某些flexible array member结尾
我不知道如何跳转或读到下一个值
你从未解释过(并且可能没有理解)你对什么类型的“价值”有所考虑。所以跳到下一个是没有意义的(没有明确的值和类型)。
也许你对C中的字符串感到困惑。读一本好书。了解什么是undefined behavior。
也许你想要一些
的数组struct yourstruct *p = calloc(10, sizeof(struct yourstruct));
if (!p) { perror("calloc failed"); exit(EXIT_FAILURE); };
类型。但是你的代码错了!例如。它将从
开始calloc
(当使用malloc
或user.res_email == req.body.res_email && user.res_empno == req.body.res_empno
进行动态内存分配时,应检查是否有失败)
答案 2 :(得分:1)
我不知道如何跳转或读取下一个值,并保持阅读 直到打印整个指针。
嗯,你已经让自己变得更加困难了。为什么? 跳转或读取内存块中的下一个值通常通过指针算术或数组索引进行处理(其中本身只是一种方便的指针算法)。
存储在数组或内存块中的顺序值的 jump 或 offset 通常由类型控制(例如{{1 },char
,int
等。)。它不一定是那种方式(正如你在其他答案中看到的那样),但它默认设置为以这种方式工作。
每个类型具有一个大小(以字节数表示),例如struct foo
,sizeof (char) = 1
(通常),sizeof (int) = 4
(x86_64上通常为sizeof (char *) = sizeof (a pointer)
或x86上为8
。类型大小控制跳转或偏移到下一个值,例如
4
通过将size_t n = 10;
int *intarray = calloc (n, sizeof *intarray); /* allocates space for 10 ints */
for (int i = 0; i < 10; i++) /* fill array, 0, 10, 20, ... 90 */
intarray[i] = i * 10;
声明为类型intarray
,编译器知道int
是第二个值的地址(例如intarray + 1
),而10
是第3个值(intarray + 2
),依此类推。 注意,由您决定不超过内存范围,例如: 20
是第10个值(OK),intarray + 9
超出了分配和调用的内存块的末尾( Undefined Behavior )。
指针算术提供了另一种从内存中的一个值跳到下一个值的简单方法。同样,这基于类型大小。
注意:您必须始终保留指向已分配内存块开头的指针,以便以后可以释放,以便跳转到intarray + 10
中的每个值,或者使用数组索引,例如intarray
,或者声明一个指向开头的第二个指针,并将其用于指针算法,例如
intarray[i]
另请注意:在尝试访问它们之前,必须初始化所有值。 (因为你使用...
int *p = intarray;
size_t i = 0;
while (i < n) { /* loop to do this 10 times */
printf ("value[%zu] : %d\n", i, *p); /* print the value stored at p */
p++; /* increment p to point to next */
}
是安全的 - 因为所有字节都被初始化为零)。但是,使用calloc
时,内存未初始化。
数组索引和指针算法适用于所有类型,甚至是malloc
等已定义的类型。这里,编译器知道struct foo { int a; int b; };
的大小,因此您可以使用指向sizeof (struct foo)
的指针,就像使用指向foo
(或int
等的指针一样。 ..)
如果您在自己身上做了很多事情,那么您正试图以char
的{{1}}间隔存储字符串(大小为0-49
字符) 。虽然这很好,但是编译器无法帮助你,你不能使用指针算法或数组索引(除非你自己动手) - 因为你构成了类型 50
。
现在您可以使用静态声明的2D数组(例如tmp
)让编译器帮助您。然后你可以使用索引(例如char + 50
或者你可以声明一个指向50个字符数组的指针,你可以使用指针算法(例如char tmp[10][50]
然后tmp[0], tmp[1], ...
来到第二个,等等..
(注意:由于C-Operator Precedence,char (*p)[50] = tmp;
周围的括号是必需的,没有您创建指向char 的指针数组的parens(50他们而不是创建一个指向数组的指针)
您还可以为任意数量的50个字符块动态分配内存。例如,为了做你想做的事情(在一个大块中),但告诉编译器你想要50个字符块(而不是你必须为其发明索引的500个字符块),你可以简单地做: / p>
p++
现在你可以简单地使用数组索引或指针算法来填充和迭代(*p)
中每个50-char块中存储的单词。
为了把整个事情放在一起,让我们举两个例子。第一个将创建一个包含10个内存块(每个50个字符)的数组,并使用数组索引来填充和迭代char (*tmp)[50]; /* 'pointer-to-array 50, type char' */
tmp = calloc (n, sizeof *tmp); /* allocate storage for 10 tmp */
的内容,第二个创建相同的内存块,但仅使用指针和一个柜台。 (两个例子完全相同):
tmp
示例使用/输出
tmp
内存使用/错误检查
在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放。
您必须使用内存错误检查程序,以确保您不会尝试在已分配的内存块的范围之外/之外进行写入,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了已分配的所有内存。
对于Linux #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NWRDS 10 /* number of words */
#define MAXC 50 /* max chars per-word */
int main (void) {
size_t n = 0; /* number of words */
char (*tmp)[MAXC]; /* 'pointer-to-array 50, type char' */
tmp = calloc (NWRDS, sizeof *tmp); /* allocate storage for 10 tmp */
if (tmp == NULL) /* validate all memory allocations */
exit (EXIT_FAILURE);
strcpy (tmp[n], "my dog has fleas."); /* copy stuff to first 3 blocks */
n++;
strcpy (tmp[n], "my cat has none.");
n++;
strcpy (tmp[n], "... lucky cat...");
n++;
for (size_t i = 0; i < n; i++)
printf ("tmp[%zu] : %s\n", i, tmp[i]);
free (tmp); /* dont' forget to free what you allocate */
return 0;
}
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。
$ ./bin/ptr2array
tmp[0] : my dog has fleas.
tmp[1] : my cat has none.
tmp[2] : ... lucky cat...
注意:正好valgrind
字节已按照您的意图分配。
始终确认已释放已分配的所有内存并且没有内存错误。
现在,让我们再次使用指针和计数器做同样的事情,
$ valgrind ./bin/ptr2array
==6010== Memcheck, a memory error detector
==6010== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6010== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==6010== Command: ./bin/ptr2array
==6010==
tmp[0] : my dog has fleas.
tmp[1] : my cat has none.
tmp[2] : ... lucky cat...
==6010==
==6010== HEAP SUMMARY:
==6010== in use at exit: 0 bytes in 0 blocks
==6010== total heap usage: 1 allocs, 1 frees, 500 bytes allocated
==6010==
==6010== All heap blocks were freed -- no leaks are possible
==6010==
==6010== For counts of detected and suppressed errors, rerun with: -v
==6010== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
(输出和内存检查相同)
虽然你的问题是基本的,但它看起来很基本,因为它涉及索引,指针算法以及两者如何直接绑定到正在处理的值的类型的基本概念。另请注意,您还可以将500
声明为#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NWRDS 10 /* number of words */
#define MAXC 50 /* max chars per-word */
int main (void) {
size_t n = 0; /* simple counter */
char (*tmp)[MAXC], (*p)[MAXC], /* 'pointer-to-array 50, type char' */
(*p2)[MAXC]; /* (3 of them) */
tmp = calloc (NWRDS, sizeof *tmp); /* allocate storage for 10 tmp */
if (tmp == NULL) /* validate all memory allocations */
exit (EXIT_FAILURE);
p = p2 = tmp; /* set all pointers equal to tmp */
strcpy (*p++, "my dog has fleas."); /* copy stuff to first 3 blocks */
strcpy (*p++, "my cat has none.");
strcpy (*p++, "... lucky cat...");
while (p2 < p)
printf ("tmp[%zu] : %s\n", n++, *p2++);
free (tmp); /* dont' forget to free what you allocate */
return 0;
}
并首先分配tmp
指针(例如char **tmp;
然后分配,复制每个字符串,例如{{1然后你可以自由地释放每个单词,然后在你完成时释放指针(这个例子留给另一天)
希望这会有所帮助。如果您有任何其他问题,请与我们联系。