所以我有一个字符串:a = 2.b 1.d; milk cheese
我通过删除所有特殊字符(等号,句号,分号)将其分离,这是使用C中的strtok函数完成的。我将每个元素都存储在一个字符串数组中,如下所示:
arr[0]="a"
arr[1]="2"
arr[2]="b"
arr[3]="1"
arr[4]="d"
arr[5]="milk"
arr[6]="cheese"
现在,我想采用这些值并将其放入结构中。这是我的结构:
struct stopPoints {
int weights[10];
char connectingPoints[10];
char *items;
int startBool;
};
我已经声明了该结构并将其命名为myPoint。现在,我想将每个单独的元素存储到我的结构中。例如,我想将“ 2”和“ 1”存储到myPoint.weights[0]
和myPoint.weights[1]
中。我要将“ a”和“ b”存储到myPoint.connectingPoints[0]
和myPoint.connectingPoints[1]
中。
我通过尝试区分字母和数字来解决这个问题。我遍历“ arr”数组,并检查每个索引是否具有字母或数字。这是通过使用ASCII值完成的(我知道根据我之前的回答,有更好的方法可以做到这一点)。但是,当我尝试打印出结构中的第一个权重元素时,会得到一个随机值。我怎样才能解决这个问题?我的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stopPoints {
int weights[10];
char connectingPoints[10];
char *items;
int startBool;
};
int main ()
{
struct stopPoints myPoint;
char *arr[30];
char str[] ="a = 2.b 1.d; milk cheese";
char * pch;
pch = strtok (str," ;=,.-");
arr[0] = pch;
int i=0;
while (pch != NULL)
{
//printf ("%s\n",pch);
pch = strtok (NULL, " ;=,.-");
arr[i+1] = pch;
printf("%s\n", arr[i]);
i++;
}
int sizeofstring = sizeof(str)/sizeof(str[0]);
int x,y=0;
for (x=0; x<sizeofstring; x++){
if (arr[y+1] >= 97 && arr[y+1] <= 122){
myPoint.connectingPoints[x] = arr[y+1];
y++;
}
else if (arr[y+1] >= 48 && arr[y+1] <= 57){
myPoint.weights[x] = arr[y+1];
y++;
}
}
printf("%d\n", myPoint.weights[1]);
return 0;
}
答案 0 :(得分:1)
首先,在细节,最小的完整和可验证的示例以及问题的格式方面做得很好。接下来,很明显你很迷路...
很难想象有一种更尴尬的方法来做自己想做的事情,但是为了学习,以笨拙的方式做事可以学到很多东西。
开始时,请勿在代码中使用魔术数字。这是为了提高代码的可读性和可维护性。 10, 30, 97, 122, 48 and 57
都是魔术数字。
#define CPWT 10 /* if you need a constant, #define one (or more) */
#define NPTR 30 /* (do not use "magic numbers" in your code) */
请勿对字符使用魔术数字。虽然您应该使用ctype.h
中为islower()
和isdigit()
提供的宏,但是如果要使用字符,请使用字符,例如if (foo >= 'a' && foo <= 'z')
不是97
和122
。只需单引号。
接下来,您每次分配arr
原因时,都会覆盖arr[i+1] = pch;
中的每个指针?
char *arr[NPTR]; /* array of 30 UNINITIALIZED pointers */
虽然strtok
确实返回了一个指针,但是当您分配arr[i+1] = pch;
时,您正在为<{1}中的每个指针分配相同的指针。完成后,arr
中的每个元素都将保存arr
返回的最后一个值(并且由于您在之后之后分配了对strtok
的最后一次调用,因此返回{{ 1}} –您很有可能会出现SegFault)
此外,在将任何内容“存储”在strtok
至NULL
的地址之前,必须根据要存储的字符串的长度分配存储空间。 (是的,即使您仅在许多元素中存储一个单个字符,您仍在存储字符串,而且每个字符串都需要一个以零结尾的字符)。
您不能在C中分配字符串(除了字符串常量的分配或在数组初始化期间)。否则,您必须复制 C字符串。
因此,由于您从arr[0]
中的未初始化,未分配的指针开始,因此必须分配然后 copy 才能将信息存储在每个指针地址。您有两种方法可以这样做:(1)arr[NPTR-1]
个字符,验证分配,然后arr
(或更有效的malloc (length + 1)
,因为您已经扫描以找到具有strcpy
的 nul-character ,或者(2)如果您有memcpy
,它将像在(1)中一样分配和复制一个函数调用。 (注意:,由于strlen()
进行了分配,因此您仍然必须验证分配成功)
示例(1)
strdup()
示例2(使用strdup
进行分配/复制)
if ((pch = strtok (str," ;=,.-")) != NULL) { /* validate each call */
size_t len = strlen (pch); /* get length */
if ((arr[0] = malloc (len + 1)) == NULL) { /* allocate/validate */
perror ("arr[0]-malloc");
exit (EXIT_FAILURE);
}
memcpy (arr[0], pch, len+1); /* copy! string to arr[0] */
i++;
}
由于您刚刚填充了strdup
的{{1}}个元素,因此无需:
/* only loop if good return from strtok */
while ((pch = strtok (NULL, " ;=,.-")) != NULL)
{
/* allocate/copy all at once with strdup (if you have it) */
if ((arr[i] = strdup (pch)) == NULL) {
perror ("arr[n]-strdup");
exit (EXIT_FAILURE);
}
i++;
}
您知道您在i
中有arr
个字符串-使用 int sizeofstring = sizeof(str)/sizeof(str[0]);
而不是i
,并逐步浏览存储在arr
中的每个字符串,而不是每个字符在i
中。这违反了标记 sizeofstring
的全部目的。此外,设置{时,您只想考虑arr
中的单个字符或单个数字字符串(而不是str
和str
) {1}}和arr
,因此请检查第二个字符是否为 nul-character ,否则请跳过"milk"
的元素。
"cheese"
和connectingPoints
都不能同时使用weights
,只有arr
y
(其中3个)中只有2个{{1 }}。如果您从connectingPoints
进行迭代,则您将尝试访问weights
中的有效数据之外的内容
同样,您不能将指针分配为字符,因此将字符串中第一个字符分配为字符的最简单方法是取消引用指针,例如a, b, d
(等效于字符connectingPoints
)。请记住,您可以这样做:
weights
(注意:分别使用计数器weights
和j = 0; j < y; ...
而不是单个*arr[x]
)
将所有部分放在一起,您可以使用以下类似的方法进行尴尬的处理:
arr[x][0]
(注意:使用 /* i contains the number of strings in arr - use it */
for (x = 0; x < i; x++) {
if (arr[x][1] == 0) { /* only consider single char strings in arr */
if (cpts < CPWT && islower(*arr[x])) { /* check bound/lowercase */
myPoint.connectingPoints[cpts] = *arr[x]; /* assign char */
cpts++;
}
else if (weights < CPWT && isdigit(*arr[x])) { /* same w/digits */
myPoint.weights[weights] = *arr[x];
weights++;
}
}
}
中的cpts
和weights
)
使用/输出示例
y
仔细检查一下,如果还有其他问题,请告诉我。
答案 1 :(得分:0)
我不太了解您要做什么,但是jq --arg keyvar "$bash_var" '.[$keyvar]' json
是一个指针数组,arr
是一个myPoint.connectingPoints
数组,而char
是一个数组myPoint.weights
中的。因此int
和myPoint.connectingPoints[x] = arr[y+1]
会做指向myPoint.weights[x] = arr[y+1]
或char
转换的指针,这通常是个坏主意。
也许你想做
int
和
myPoint.connectingPoints[x] = arr[y+1][0];
与myPoint.weights[x] = arr[y+1][0];
的比较也是如此。 97、122、48和57不是硬编码的内存地址,对吗?
这完全忽略了arr[y+1]
和myPoint.connectingPoints
中缓冲区溢出的事实。提示:myPoint.weights
大于10。
请始终使用sizeofstring
进行编译。该标志存在是有原因的
答案 2 :(得分:0)
您不会在任何时候初始化结构,而是通过分配值来进行替换 到myPoint.connectionPoints [x]和myPoint.weights [x],但随后跳过另一个 数组,这就是您获得随机值的原因
if (arr[y+1] >= 97 && arr[y+1] <= 122){
myPoint.connectingPoints[x] = arr[y+1]; // myPoint.weights[x] left unassigned
y++;
}
else if (arr[y+1] >= 48 && arr[y+1] <= 57){
myPoint.weights[x] = arr[y+1]; // myPoint.connectingPoints[x] left unassigned
y++;
}
我建议您在获得 从strtok返回值,以避免为以后不分配的内容分配 需要。
例如
int index = 0;
for (char* pch = strtok(str, " ;=,.-"); pch != NULL; pch = strtok(NULL, " ;=,.-")
{
switch (index++)
{
case 0:
case 1:
case 2:
...
default:
break;
}
}
编辑:实际上我不确定您是否完全需要该开关,只是为每个数组都有一个计数器,并在分配给它时递增。
对于返回值strtok()
,您必须注意为返回值分配内存,以便在每次迭代之间存储该值,因为它在返回令牌时使用原始字符串的静态缓冲区,但是如果您直接转换令牌,则不需要。
当您检查字符的值时,请使用标准c运行时之一 用于此目的的函数isdigit()isalpha()/ islower()而不是检查ASCII 直接值。