Во-первых, очень хорошая работа над деталями, минимально полным и поддающимся проверке примером и форматированием вашего вопроса.Далее, очевидно, что вы совершенно растеряны ...
Трудно представить более неловкий подход к тому, что вы пытаетесь сделать, но ради обучения есть немало обучения.это можно сделать, делая это неловко.
Для начала, не используйте магические числа в своем коде.Это для удобства чтения и обслуживания по мере роста вашего кода.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;
, вы назначаете одинаковый указатель каждому указателю в arr
.Когда вы закончите, каждый элемент в arr
будет содержать последнее значение, возвращаемое strtok
(и поскольку вы присваиваете после , последний вызов strtok
возвращает NULL
- вы, скорее всего, SegFault)
Кроме того, перед тем, как что-либо «хранить» по адресу от arr[0]
до arr[NPTR-1]
, вы должны выделить хранилище в зависимости от длины сохраняемой строки.(и да, даже если вы сохраняете односимвольный во многих элементах, вы сохраняете строки - и каждая строка требует завершающий ноль символ ).
Вы не можете назначать строки в C (кроме назначения строковых литералов или во время инициализации массива).В противном случае вы должны скопировать строк в C.
Так как вы начинаете с неинициализированных, нераспределенных указателей в arr
, вы должны выделить а затем copy для хранения информации по каждому адресу указателя.У вас есть два способа сделать это: (1) либо malloc (length + 1)
символов, проверить выделение, а затем strcpy
(или более эффективно memcpy
, так как вы уже отсканировали, чтобы найти nul-символ с strlen()
) или (2) если у вас есть strdup()
, он будет выделять и копировать, как вы это делали в (1), за один вызов функции.( примечание: , поскольку strdup
выделяет, вы все равно должны проверить выделение выполнено успешно)
Пример (1)
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++;
}
Пример 2(используя strdup
для выделения / копирования)
/* 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
.Кроме того, вы хотите учитывать только один символ или одну цифру строки в arr
(не "milk"
и "cheese"
) при установке connectingPoints
и weights
, поэтомупроверьте, является ли второй символ nul-символом , в противном случае пропустите элемент arr
.
Вы не можете использовать y
для connectingPoints
и weights
,у вас есть a, b, d
connectingPoints
(3 из них) и только 2 weights
.Вы попытаетесь получить доступ за пределами допустимых данных в weights
, если вы выполняли итерацию с j = 0; j < y; ...
Опять же, вы не можете назначить указатель как символ, поэтому самый простой способ назначить 1-й символ в строкекак символ, это просто разыменование указатель, например *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
)
Собрав все части воедино, вы можете сделать неловкий подход с помощью чего-то вроде следующего:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define CPWT 10 /* if you need a constant, #define one (or more) */
#define NPTR 30 /* (do not use "magic numbers" in your code) */
struct stopPoints {
int weights[CPWT];
char connectingPoints[CPWT];
char *items;
int startBool;
};
int main (void)
{
struct stopPoints myPoint = { .weights = {0} };
char *arr[NPTR]; /* array of 30 UNINITIALIZED pointers */
char str[] ="a = 2.b 1.d; milk cheese";
char *pch;
int i = 0, x, cpts = 0, weights = 0;
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++;
}
/* 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 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++;
}
}
}
puts ("arr contents:");
for (x = 0; x < i; x++)
printf (" arr[%2d]: %s\n", x, arr[x]);
puts ("\nconnectingPoints:");
for (x = 0; x < cpts; x++)
printf (" myPoint.connectionPoints[%2d]: %c\n",
x, myPoint.connectingPoints[x]);
puts ("\nweights:");
for (x = 0; x < weights; x++)
printf (" myPoint.weights[%2d]: %c\n",
x, myPoint.weights[x]);
return 0;
}
( примечание: использование islower()
и isdigit()
изctype.h
)
Пример использования / вывода
$ ./bin/strtokarrptrs
arr contents:
arr[ 0]: a
arr[ 1]: 2
arr[ 2]: b
arr[ 3]: 1
arr[ 4]: d
arr[ 5]: milk
arr[ 6]: cheese
connectingPoints:
myPoint.connectionPoints[ 0]: a
myPoint.connectionPoints[ 1]: b
myPoint.connectionPoints[ 2]: d
weights:
myPoint.weights[ 0]: 2
myPoint.weights[ 1]: 1
Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.