I've been trying to understand why my string/char array loses the value assigned to it in the for loop as soon as the loop ends. The value for token2 is a user input that gets shunted into the "token2" variable earlier on in the code. I have several checks prior to this portion and token2 is populated as expected.
int dayInt2;
char dayToken2[3];
//For loop to parse out the month portion of second token.
for (int i = 3; i < 5; i++)
{
dayToken2[i] = token2[i];
printf("For loop parse: %c\n", token2[i]);
}
dayToken2[3] = '\0'; //Add null pointer to the last character space of the string array.
printf("dayToken2 value: %s\n", dayToken2); //Debugging to check the value in dayToken2.
dayInt2 = atoi(dayToken2); //converts day
printf("dayInt2 value: %s\n", dayInt2); //Debugging to check if the string conversion to int worked.
dayToken2[3] is outside the array. The indexes are from zero. So the maximum index is 2.
printf("dayInt2 value: %s\n", dayInt2); is wrong. You try to print the integer but you say the printf that it should expect the string. It has to be printf("dayInt2 value: %d\n", dayInt2);
dayToken2[i] = token2[i]; is also wrong as i changes from 3 to 4. It has to be dayToken2[i - 3] = token2[i];. You can use memcpy for that memcpy(dayToken2, token2 + 3, 2);
When defining your char array, you set the max indices as 3, so there is only dayToken[0], dayToken[1], dayToken[2]. In your for loop you set i from 3-5, try doing from 0-2.
Related
I'm pretty new to C, and I'm trying to write a function that takes a user input RAM size in B, kB, mB, or gB, and determines the address length. My test program is as follows:
int bitLength(char input[6]) {
char nums[4];
char letters[2];
for(int i = 0; i < (strlen(input)-1); i++){
if(isdigit(input[i])){
memmove(&nums[i], &input[i], 1);
} else {
//memmove(&letters[i], &input[i], 1);
}
}
int numsInt = atoi(nums);
int numExponent = log10(numsInt)/log10(2);
printf("%s\n", nums);
printf("%s\n", letters);
printf("%d", numExponent);
return numExponent;
}
This works correctly as it is, but only because I have that one line commented out. When I try to alter the 'letters' character array with that line, it changes the 'nums' character array to '5m2'
My string input is '512mB'
I need the letters to be able to tell if the user input is in B, kB, mB, or gB.
I am confused as to why the commented out line alters the 'nums' array.
Thank you.
In your input 512mB, "mB" is not digit and is supposed to handled in commented code. When handling those characters, i is 3 and 4. But because length of letters is only 2, when you execute memmove(&letters[i], &input[i], 1);, letters[i] access out of bounds of array so it does undefined behaviour - in this case, writing to memory of nums array.
To fix it, you have to keep unique index for letters. Or better, for both nums and letters since i is index of input.
There are several problems in your code. #MarkSolus have already pointed out that you access letters out-of-bounds because you are using i as index and i can be more than 1 when you do the memmove.
In this answer I'll address some of the other poroblems.
string size and termination
Strings in C needs a zero-termination. Therefore arrays must be 1 larger than the string you expect to store in the array. So
char nums[4]; // Can only hold a 3 char string
char letters[2]; // Can only hold a 1 char string
Most likely you want to increase both arrays by 1.
Further, your code never adds the zero-termination. So your strings are invalid.
You need code like:
nums[some_index] = '\0'; // Add zero-termination
Alternatively you can start by initializing the whole array to zero. Like:
char nums[5] = {0};
char letters[3] = {0};
Missing bounds checks
Your loop is a for-loop using strlen as stop-condition. Now what would happen if I gave the input "123456789BBBBBBBB" ? Well, the loop would go on and i would increment to values ..., 5, 6, 7, ... Then you would index the arrays with a value bigger than the array size, i.e. out-of-bounds access (which is real bad).
You need to make sure you never access the array out-of-bounds.
No format check
Now what if I gave an input without any digits, e.g. "HelloWorld" ? In this case nothin would be written to nums so it will be uninitialized when used in atoi(nums). Again - real bad.
Further, there should be a check to make sure that the non-digit input is one of B, kB, mB, or gB.
Performance
This is not that important but... using memmove for copy of a single character is slow. Just assign directly.
memmove(&nums[i], &input[i], 1); ---> nums[i] = input[i];
How to fix
There are many, many different ways to fix the code. Below is a simple solution. It's not the best way but it's done like this to keep the code simple:
#define DIGIT_LEN 4
#define FORMAT_LEN 2
int bitLength(char *input)
{
char nums[DIGIT_LEN + 1] = {0}; // Max allowed number is 9999
char letters[FORMAT_LEN + 1] = {0}; // Allow at max two non-digit chars
if (input == NULL) exit(1); // error - illegal input
if (!isdigit(input[0])) exit(1); // error - input must start with a digit
// parse digits (at max 4 digits)
int i = 0;
while(i < DIGITS && isdigit(input[i]))
{
nums[i] = input[i];
++i;
}
// parse memory format, i.e. rest of strin must be of of B, kB, mB, gB
if ((strcmp(&input[i], "B") != 0) &&
(strcmp(&input[i], "kB") != 0) &&
(strcmp(&input[i], "mB") != 0) &&
(strcmp(&input[i], "gB") != 0))
{
// error - illegal input
exit(1);
}
strcpy(letters, &input[i]);
// Now nums and letter are ready for further processing
...
...
}
}
I have one long array, and I'm trying to figure out how to split it up into two separate arrays, the second array has the right contents but the first is empty, I'm also getting an Abort Trap:6 and I'm not sure what that means.
I have an array called entireA, which looks something like this:
HELLO:WORLD, I want to put HELLO in a separate array (firstA) and WORLD in secondA. When I print first and second array at the end, secondA has the right contents but firstA doesn't event though I'm printing to check if the right characters are being passed over and they are -- but the firstA is still empty and I'm getting and abort trap i don't understand.
I've just started learning C, why is the first array empty and what does the error mean?
#define ARRSIZE 10000
char entireA[ARRSIZE] = "";
char firstA[ARRSIZE] = "";
char secondA[ARRSIZE] = "";
strcpy(entireA,"HELLO:WORLD\n");
int firstVar = 0;
int entireVar = 0;
while(entireA[entireVar] != ':') {
if(entireA[entireVar] == ';') {
break;
}
printf("%c \n",entireA[entireVar]);
firstA[firstVar] = entireA[entireVar];
firstVar++;
entireVar++;
}
firstA[firstVar] = '\0';
int secondVar = 0;
entireVar++; //skip ':'
while(entireA[entireVar] != '\n') {
secondA[secondVar] = entireA[entireVar];
secondVar++;
entireVar++;
}
secondA[secondVar] = '\0';
printf("%s", firstA);
printf("%s", secondA);
There is nothing wrong with the code you posted.
After execution, the variables have the following values:
entireA 0x02efcdb4 "HELLO:WORLD\n" char[0x00002710]
entireVar 0x0000000b int
firstA 0x02efa69c "HELLO" char[0x00002710]
firstVar 0x00000005 int
secondA 0x02ef7f84 "WORLD" char[0x00002710]
secondVar 0x00000005 int
Whatever your problem is, it's most likely something to do with your environment. I would suggest reducing the value of ARRSIZE to, say 80 characters, and seeing if that changes your results.
Below is a section of a Tokenizer I built. The user types a string they wish to tokenize, that string is stored into a char array, and a null character ('\0') is placed as soon as the string ends. That section of the code seems to work fine after having tested it a few times.
The problem I'm getting occurs later on in the code when I make an array (tokenArray) of arrays (newToken). I use functions to get number of tokens and token length.
I entered the string "testing pencil calculator." I then store each token into an array. The problem is when I go to print the contents of the array, the loop that I have printing stops before it should.
Here's a sample input/output. My comments (not in code) noted by
$testing pencil calculator //string entered
complete index: 0 //index of the entire array, not the tokenized array
token length: 7 //length of 1st token "testing"
pointer: 0xbf953860
tokenIndex: 0 //index of the token array (array of arrays)
while loop iterations: 4 //number of times the while loop where i print is iterated. should be 7
test //the results of printing the first token
complete index: 8
token length: 6 //next token is "pencil"
tokenIndex: 1
while loop iterations: 5 //should be 6
penci //stops printing at penci
complete index: 15
token length: 10 //final token is "calculator"
pointer: 0xbf953862
tokenIndex: 2
while loop iterations: 5 //should be 10
calcu //stops printing at calcu
for the life of me, I simply cannot figure out why the while loop is exiting before it is supposed to. I doubt this is the only problem with my methodology, but until I can figure this out, I can't address other bugs.
Below is a section of my code that is responsible for this:
from main:
completeString[inputsize] = '\0';
char tokenArray[numTokens+1];
tokenArray[numTokens] = '\0';
putTokensInArray(tokenArray, completeString);
method where I'm getting errors:
char ** putTokensInArray(char tokenArray[], char * completeString){
int completeIndex = 0;
int tokenIndex = 0;
while(tokenArray[tokenIndex] != '\0'){
int tokenLength = tokenSize(completeString, completeIndex);
char newToken [tokenLength+1];
newToken[tokenLength] = '\0';
tokenArray[tokenIndex] = *newToken;
printf("\ncomplete index: %d", completeIndex);
printf("\ntoken length: %d", tokenLength);
printf("\ntokenIndex: %d\n", tokenIndex);
int i = 0;
while(newToken[i] != '\0'){
newToken[i] = completeString[i + completeIndex];
i++;
}
completeIndex += (tokenLength+1);
printf("while loop iterations: %d\n", i);
for(int j = 0; newToken[j] != '\0'; j++){
printf("%c", newToken[j]);
}
tokenIndex++;
tokenLength = 0;
}//big while loop
}//putTokensInArray Method
I have tried several things but just cannot get the grasp of it. I'm new to C, so it's entirely possible I'm making pointer mistakes or accessing memory I shouldn't be; on that note, how would I implement a malloc() and free()? I've been doing reading on that and seems to work, but I'm unable to implement those functions.
You are passing an uninitialized character array to your function putTokensInArray. Later in that function, in the while loop condition you are checking for \0 for every element starting from 0. However since the array is uninitialized, those characters could be ANY characters. There could be a \0 before the numTokens+1th element.
To fix this problem, pass the length of the character array i.e. numTokens to the putTokensInArray as an additional argument. Then in your while loop, do the following condition check instead:
while(tokenIndex < numTokens){
So I have this function :
char *lookUpPageTable(char **array, int VPN)
{
if (array[VPN][0] == '1')
{
/*char **pageNumber = (char **)malloc(sizeof(char*)* 128);
for (int i = 0; i < strlen(array); i++)
{
pageNumber[i] = array[VPN][i];
}*/
return array[VPN]; //this returns the whole number which I dont want
}
else
{
return "Page Fault";
}
}
The array I'm passing in as a parameter holds a list of numbers in the form 1 123456 where the first number is either a 1 or a 0 and the second number is a random number. This function checks the first number at index VPN in the array. If it is a zero, it should return a "Page Fault" string. If it is a 1, then the function should return the number after the 1.
For example, if i called lookUpPageTable(array, index)
The method should see if array[index][0] == '1'
If it does then return the remaining numbers at array[index]
else
return "page fault"
array[VPN] is the VPN-th element of the array, which happens to be a pointer to the string "1 123456" as you say. If you return array[VPN] + 1, for example, it would be a pointer to the string " 123456".
So you may return array[VPN] + 2, and you will obtain a pointer to the string "123456" as desired.
Note, however, that I am relying on your guarantee that the string's contents are indeed something of the form "1 123456", and I would recommend that your code should also verify that the string really is of that form.
When a coordinate is selected, it should be replaced with a "~". However, it's being replaced with the ascii value for the ~ instead (126). I tried a few different things, but I always get the 126 instead of the ~. Any ideas?
Thanks for the help!
int board_is_empty(int N, int board[ROWS][COLS])
{
int i = 0, j = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
if (board[i][j] != '~')
{
return 0;
}
}
}
return 1;
}
//updates the board to replace each selected coordinate with a ~.
//returns nothing
void update_board (int board[ROWS][COLS], int row_target, int column_target)
{
board[row_target][column_target] = '~';
}
int main(void)
{
int game_board[ROWS][COLS] = {0};
int rows, columns = 0;
int players_turn = 1, target_column = -1, target_row = -1, value = 0;
int row_selection = 0, column_selection = 0;
int i = 0;
initialize_game_board(game_board);
display_board(game_board);
generate_starting_point(game_board, &rows, &columns);
printf ("\nPlease hit <Enter> to continue.\n");
getchar ();
while (board_is_empty(ROWS, game_board) != 1)
{
select_target (&target_row, &target_column, players_turn);
value += game_board[target_row][target_column];
update_board (game_board, target_row, target_column); //should cause the coordinates at target_row && target_column to be replaced with a ~
display_board(game_board);
}
printf("\n%d", value);
}
'~' is a character and you have declared board as a two dimensional integer array.
so when you write board[row_target][column_target] = '~';
it convert '~' it into integer i.e into its ascii value which is 126
and there for it becomes board[row_target][column_target] = 126
I will suggest make board as two dimensional character array. Hopefully it will solve your problem.
And in case if you want it as integer only then consider 126 as a special no which means '~' by declaring
For storing your coordinates, you are using an integer array. When you execute
board[row_target][column_target] = '~'; tilde's ascii value (126) is assigned to LHS. There is no way you can assign a character to an integer value. I think you should use some special number rather than tilde. If I were you, I would use INT_MIN or INT_MAX.
There isn't a difference between the character '~' and the number 126 as far as the C language is concerned, '~' == 126.
(You used "~" which i would normally use for a string, but i assume you don't actually mean that).
If you want to display a value, you have to use the correct format string. %d is for decimal integers, %c would be for characters (the variable holding the value should also be a char)
In C, chars are just integers. At output time they are represented as characters but internally they hold just the ASCII code of that character.
Since your board is a matrix of int's, when you assign '~' you are effectively assigning the number 126 to a position of the board. If you check that position, the expected result is to get an int equal to 126.
However, if you want to see that value as a character, you can do it by casting that number into a char:
printf("%c", value);
Take a look:
#include <stdio.h>
int main()
{
int i = '~';
char c = '~';
printf("Integer: %d\n", i); /* outputs: 126 */
printf("Char: %c\n", c); /* outputs: ~ */
printf("Integer casted to char: %c\n", i); /* outputs: ~ */
}
That is, your value is right. You just need to get the representation you want. (If you want to be able to store the value 126 in the board and the character ~ at the same time, then you're out of luck because for C they are the same thing -you can use some other value that you know that the board isn't going to hold, like -1 or something like that).
Update:
So, if I didn't get it wrong what you're trying to do is to read numbers from a bidimensional matrix of random integers and mark each one as you go reading them.
If that is what you're trying to achieve, then your idea of using '~' to mark the read positions isn't going to work. What I meant before is that, in C, 126 and the character '~' are the exact same thing. Thus, you won't be able to differentiate those positions in which you have written a '~' character and those ones in which a random 126 is stored by chance.
If you happen to be storing positive integers in your array, then use -1 instead of '~'. That will tell you if the position has been read or not.
If you are storing any possible random integer, then there is nothing you can store in that array that you can use to mark a position as read. In this case a possible solution is to define your array like this:
typedef struct {
int value;
char marked;
} Position;
Position board[ROWS][COLS];
Thus, for each position you can store a value like this:
board[row][col].value = 23123;
And you can mark it as read like this:
board[row][col].marked = 'y';
Just, don't forget to mark the positions as not read (board[row][col].marked = 'n';) while you fill the matrix with random integers.