How to convert using atoi and strtok with multidimesional arrays? - arrays

Okay so i have this mltidim array filled with these numbers,
i wish to convert them into ints at the locations
So its gonna be a int multidim arrayint intarray[2][5][12];
Any tip on getting the converter to solve the issue? ive been on this problem a while and it
feels like im close!!
char chararray[2][5][40] =
{
{
{"307,07,33,307,11,44,307,12,31,307,16,10"},
{"308,07,52,308,11,52,308,12,35,308,16,18"},
{"309,07,24,309,11,40,309,12,30,309,16,14"},
{"310,07,15,310,11,38,310,12,36,310,16,27"},
{"311,07,12,311,11,47,311,12,30,311,16,12"}
},
{
{"314,07,12,314,11,34,314,12,27,314,16,52"},
{"315,07,15,315,11,49,315,12,31,315,16,13"},
{"316,07,59,316,11,44,316,12,38,316,16,42"},
{"317,07,52,317,11,41,317,12,30,317,16,12"},
{"318,08,03,318,11,32,318,12,39,318,16,07"}
}
};
And this is how i am trying to convert but it doesnt even let me debug just a weird error pops up..
int intarray[2][5][12];
for(int i = 0; i < 2 ; i++){
for(int j = 0; j < 5;j++){
for(int k = 0; k < 40;k++){
intarray[i][j][k] = atoi(strtok(chararray[i][j][k],","));
}
}
}

intarray[i][j][k] for i==0, j==0, k==0, represents 3 which is the the character residing at intarray[0][0][0]. This is a single char and cannot be processed using strtok().
What you really want to pass to strtok() is a complete null terminated string:
char chararray[0][0]
which is the 40 character buffer containing "307,07,33,307,11,44,307,12,31,307,16,10".
But because you probably do not want to destroy the array, you should start of by getting a duplicate of the string, something like this:
int intarray[2][5][12] = {{0}};//zero before using
int i=0;
char *dup = strdup(chararray[0][0]);//in your actual code this will be in
//a loop of `i,j` indexes, each one
//yielding the character buffers:
//{"307,07,33,307,11,44,307,12,31,307,16,10"},
//{"308,07,52,308,11,52,308,12,35,308,16,18"},
//{"309,07,24,309,11,40,309,12,30,309,16,14"},
//{"310,07,15,310,11,38,310,12,36,310,16,27"},
//{"311,07,12,311,11,47,311,12,30,311,16,12"}
//{"314,07,12,314,11,34,314,12,27,314,16,52"},
//{"315,07,15,315,11,49,315,12,31,315,16,13"},
//{"316,07,59,316,11,44,316,12,38,316,16,42"},
//{"317,07,52,317,11,41,317,12,30,317,16,12"},
//{"318,08,03,318,11,32,318,12,39,318,16,07"}
if(dup)
{
tok = strtok(dup, ",\n");
while(tok)
{
intarray[0][0][i] = atoi(tok);
tok = strtok(NULL, ",\n");
i++;
}
free(dup);//so you can use it again and again for the other sub-strings.
....
Following this approach, all of the other strings can be parsed into intarray

Each chararray[i][j] is a string - chararray[i][j][k] is a single character in that string. Unfortunately, you're passing the single character to strtok when it expects the address of the first element of the string.
When you're tokenizing repeated elements in a string, you only pass the base address once, then pass NULL for the remainder of the string. So your loop would need to be
for(int i = 0; i < 2 ; i++){
for(int j = 0; j < 5;j++){
intarray[i][j][0] = atoi( strtok( chararray[i][j], "," ) );
for(int k = 1; k < 40;k++){
intarray[i][j][k] = atoi( strtok( NULL, "," ) );
}
}
}
Note that this assumes your input is always well-formed - there's no sort of error or sanity checking.

Related

Extracting words from a string into dynamic 2D char array

I have a dynamic char array that contains a string. I'm trying to extract all the words from this string into a dynamic 2d char array. Here's my code:
int rows = 1;
char *input_words = malloc((rows)*sizeof(char));
input_words = lowerCase(getInputWords(MAX_LINE_LEN, input_file)); //retrieves a string of words
char **input_words_tokenized = malloc((wordCount(input_words))*sizeof(char));
for(i = 0; i < wordCount(input_words); i++) {
input_words_tokenized[i] = malloc(MAX_KEY_LEN*sizeof(char));
}
char *t = strtok(input_words, " ");
j = 0;
while(t) {
for(i = 0; i < strlen(t); i++) {
strcpy(&input_words_tokenized[j][i], &t[i]);
printf("%c", input_words_tokenized[j][i]);
}
j++;
t = strtok(NULL, " ");
}
In my output, input_words_tokenized[j][i] only contains the first word or token from input_words. Why aren't the remaining words being tokenized and stored into input_words_tokenized[j][i]?
At least one issue.
Incorrect size calculation.
char **input_words_tokenized =
malloc((wordCount(input_words))*sizeof(char));
// wrong type ^--^
Instead of sizing to the hopefully matching type, size to the referenced type. It is easier to code right, review and maintain.
char **input_words_tokenized =
malloc((wordCount(input_words)) * sizeof *input_words_tokenized);
// ^--------------------^

How to input string tokens into a 2d array?

Trying to get a list of inputs with delimiter "|":
Public|Jane|Q|Ms.|600|Maple Street|Your Town|Iowa|12345
And then would like to input them into a 2d array (customerData) that I can manipulate.
I realize I'm missing int main() and code for reading file/input. Just including the relevant code. I can get the input, its the putting into customerData getting out of that I'm struggling with.
#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS 9
char input[INPUT_LENGTH];
char customerData[NUM_FIELDS][FIELD_LENGTH];
int element = 0;
int customer = 0;
while ( fgets( input, INPUT_LENGTH, data ) != NULL ) {
char* token = strtok(input, "|"); // start tokeninzing
while (token) { // end of string last token is NULL
strcpy(customerData[customer][element], token);
token = strtok(NULL, "|");
element++;
}
customer++;
}
for (int i = 0; i < entry; i++) {
for (int k = 0; k < element; k++) {
printf("%s\n", customerData[i][k]);
}
}
I'm expecting output like this:
Public
Jane
Q
Ms.
600
Maple Street
Your Town
Iowa
12345
the posted code keeps adding 1 to element, even when it is a new line/new customer.
Suggest, after the statement:
customer++;
to insert the statement:
element = 0;
also regarding:
char customerData[NUM_FIELDS][FIELD_LENGTH];
I would expect the first part of the array to be a customer number, then NUM_FIELDS and then FIELD_LENGTH
Also, for clarity suggest element be replaced with fieldNum

How to read an unknown number of float values from a STRING

I have a string that has unknown number of float values separated by a white space.(something like this):
12.55 54.11 -1.00000 2.222 ...
Now i need to read all those values into an array.
How do I do this? Do I have to use sscanf?
Do I have to use sscanf?
No, you do not have to, unless you prefer to use it. I would prefer using strtof.
Regardless of the function that you use, you would need to use a loop that reads the values from the string. Since the number of items is unknown, you could scan the string twice - once to learn how many items you have, and a second time to do the actual read. Since the string is in memory, the wasted time in the loop that counts the entries will not be significant.
int cnt = 0;
char *str = "2.55 54.11 -1.00000 2.222";
char *ptr = str, *eptr;
do {
strtof(ptr, &eptr);
ptr = eptr;
cnt++;
} while (*eptr);
printf("%d\n", cnt);
float *res = malloc(cnt*sizeof(float));
ptr = str;
for (int i = 0 ; i != cnt ; i++) {
res[i] = strtof(ptr, &eptr);
ptr = eptr;
}
for (int i = 0 ; i != cnt ; i++) {
printf("%f\n", res[i]);
}
Demo on ideone.

Concat LPSTR in C

Trying to use as basic C as I can to build a list of numbers from 1-52 in a random order (deck of cards). Everything works, but all of my attempts to concat the strings and get a result end in failure. Any suggestions? NOTE: This is not homework it's something I'm using to create a game.
// Locals
char result[200] = ""; // Result
int card[52]; // Array of cards
srand(time(0)); // Initialize seed "randomly"
// Build
for (int i=0; i<52; i++) {
card[i] = i; // fill the array in order
}
// Shuffle cards
for (int i=0; i<(52-1); i++) {
int r = i + (rand() % (52-i));
int temp = card[i]; card[i] = card[r]; card[r] = temp;
}
// Build result
for (int c=0; c<52; c++) {
// Build
sprintf(result, "%s%d", result, card[c]);
// Comma?
if ( c < 51 )
{
sprintf(result, "%s%s", result, ",");
}
}
My end result is always garbled text. Thanks for the help.
You keep writing to the same position of "result".
sprintf is not going to do the appending for you.
You may consider, after each sprintf, get the return value (which is the number of char written), and increment the pointer to result buffer. i.e. something like:
(psuedo code):
char result[200];
char * outputPtr = result;
for (int c=0; c<52; c++) {
// Build
int n = sprintf(outputPtr, "%d%s", card[c], (c<51 ? "," : ""));
outputPtr += n;
}
Are we writing C++ or C? In C++, concat-ing a string is just:
string_out = string_a + string_b
…since you'd be using std::string.
Furthermore, if this is C++, the STL has a std::shuffle function.
If this is C, note that all your sprintfs aren't concatenating strings, they're just overwriting the old value.
I think, if memory serves, that sprintf will always write into the buffer starting at byte 0. This means that you would be writing the first couple of bytes over and over again with a number, then a comma, then a number. Check if your first bytes are ",[0-9]" - if so, that's your issue.
This would add a comma between each number in the result string:
// Get a pointer to the result string
char* ptr = &result[0];
for (int c = 0; c < 52; c++) {
// Add each cards number and increment the pointer to next position
ptr += sprintf(ptr, "%d", card[c]);
// Add a separator between each number
if (c < 51) {
*ptr++ = ',';
}
}
// Make sure the result string is null-terminated
*ptr = 0;

Reverse Array of C-Strings

I have a few questions regarding array of strings in C.
I have an array char *string. I have a char *string and then I split every 4 characters in a array of strings called sep_str. So for example if char *string = 'The sum';, then char **sep_str is:
0: |_| --> "The "
1: |_| --> "Sum"
My first question is, in an array of strings in C (so array of array of chars), will there be a null terminating character at the end of each sep_str[i], or just at the last position of sep_str? Here is how I copy string into an array of strings:
for (int i = 0; i < str_length; i++) {
sep_str[i/4][i%4] = *ptr;
ptr++;
}
My second question is, how would I reverse the elements of each string in sep_str? Here's how I did it, but I feel like it is stepping out of the array of the substring. (so out of the element of the sep_str):
// Reverse each element in the array
char temp;
for (int i = 0; i < num_strs; i++) {
for (int j = 0, k = 4; j < k; j++, k--) {
temp = sep_str[i][j];
sep_str[i][j] = sep_str[i][k];
sep_str[i][k] = temp;
}
}
The copy of the strings sounds good to me. Since each string has always 4 chars, you can avoid the null terminator \0. Alternatively you need to declare sep_str as a 5x(lenght/4) matrix, to store the \0 char at the end of each string.
To reverse a string you need to iterate from the start to the middle of the string, replacing the i-th char with the length-i-1-th. You need to replace the inner for replacing k=3 to k=2.
You also need to take care of the last string, since the lenght might not be multiple of four.
char temp;
for (int i = 0; i < (num_strs - 1); i++) {
for (int j = 0, k = 3; j < k; j++, k--) {
temp = sep_str[i][j];
sep_str[i][j] = sep_str[i][k];
sep_str[i][k] = temp;
}
}
if (num_strs > 0) {
for (int j = 0, k = strlen(sep_str[i]) - 1; j < k; j++, k--) {
temp = sep_str[i][j];
sep_str[i][j] = sep_str[i][k];
sep_str[i][k] = temp;
}
}
In a C string, there will be only one termination character. But if you need to tokenize the strings, then each string must be null terminated.
But before that -
char *string = "The sum"; // should be const char* string = "The sum";
String literal in the above case resides in read only location and cannot be modified. If you need to modify, then
char string[] = "The sum";
If you don't have the terminating character in your strings then yes, you will be outside the bounds of the array since you are accessing sep_str[i][4], which is not a valid location:
sep_str[0] = 'T'
sep_str[1] = 'h'
sep_str[2] = 'e'
sep_str[3] = ' '
However, I doubt that you want to have the null character at the beginning of your string, so you need k=3 in your for loop, not k=4.
My first question is, in an array of strings in C (so array of array of chars), will there be a null terminating character at the end of each sep_str[i], or just at the last position of sep_str?
Only at the end, but if you want to treat each individual chunk as its own string, you'll need to add the \0 yourself.
My second question is, how would I reverse the elements of each string in sep_str?
You could do it with pointers...
char temp;
// Point to start of string, `str` will decay to first memory position.
char *start = str;
// Point to the end of the string. You will need to `#include <string.h>`
// for `strlen()`. Otherwise, write a `while` loop that goes until `\0` to find
// the last position.
char *end = &str[strlen(str) - 1];
// Do until we hit the middle of the string.
while (start < end) {
// Need a temp char, no parallel assignment in C.
temp = str[start];
// Swap chars.
str[start++] = str[end];
str[end--] = str[temp];
}
Assuming str is your string.

Resources