I was trying to make a 'decimal to binary' program. It should convert from 0 to 255 only and it does.
I have two variables, 'n' and 'temp', when the user first enters the number I store it on 'n'. Then I assign 'n' to 'temp' (thus creating a copy, at least that's what I think I'm doing).
then I only use 'temp' in my code. I never use 'n', not until the end where I decide to print the number the user entered. And here comes the problem, if I enter a number greater than 255, the variable 'n' changes to 1.
I tried running my code through a couple C online compilers and all of them output the variable 'n' the right way, meaning that despite the binary not working when the numbers is greater than 255 (as intended) they print the entered value.
I found one online compiler where it doesn't print the 'n' variable if its greater than 255.
https://www.tutorialspoint.com/compile_c_online.php
If you run my code through this compiler, you'll see how the variable 'n' changes to 1 without it being used.
I know the 'binary part' won't work if you use a number greater than 255. I want to know why 'n' changes out of nowhere.
#include <stdio.h>
int main()
{
int bin[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int arrSize = 7;
int n;
int temp;
scanf("%d", &n);
temp = n;
while(temp != 0)
{
bin[arrSize] = temp % 2;
temp = temp / 2;
arrSize = arrSize - 1;
}
printf(" Decimal: %d ----> binary: ", n);
for(int i = 0; i <= 7; i++)
{
printf("%d", bin[i]);
}
printf("\n");
return 0;
}
You've run through a "Buffer overflow".
A quick definition for that:
A buffer overflow occurs when a program or process attempts to write
more data to a fixed length block of memory, or buffer, than the
buffer is allocated to hold. Since buffers are created to contain a
defined amount of data, the extra data can overwrite data values in
memory addresses adjacent to the destination buffer unless the program
includes sufficient bounds checking to flag or discard data when too
much is sent to a memory buffer.
The error in your code remains in this while loop:
while(temp != 0){
//I added this line to make it clear
printf("inside loop\tarrSize=%d\n",arrSize);
bin[arrSize] = temp % 2;
temp = temp / 2;
arrSize = arrSize - 1;
}
For an input equals to 300 (The error will occur for each input > 255) you'll have this output:
inside loop arrSize=7
inside loop arrSize=6
inside loop arrSize=5
inside loop arrSize=4
inside loop arrSize=3
inside loop arrSize=2
inside loop arrSize=1
inside loop arrSize=0
inside loop arrSize=-1
inside loop arrSize=0
The problem is that we have an index equals to -1, You'll ask what will happen ? well in fact arrays are pointers to the address of the first element of the table + the offset (index * size of the type of the table) which means that for bin[-1] it is in fact arrSize, and bin[-2] is in fact n.
You can check this by verifying the addresses as it follows:
printf("# of bin[-1]:\t%p\n",(void*)&bin[-1]);
printf("# of arrSize:\t%p\n\n",(void*)&arrSize);
printf("# of bin[-2]:\t%p\n",(void*)&bin[-2]);
printf("# of n:\t\t\t%p\n",(void*)&n);
which with my compiler gave me:
# of bin[-1]: 0x7ffe00e32f9c
# of arrSize: 0x7ffe00e32f9c
# of bin[-2]: 0x7ffe00e32f98
# of n: 0x7ffe00e32f98
So you changes without knowing bin[-1] (or bin[-2] according to the value of n) which is in fact arrSize (or n)..
How you can fix this ? I advice you to verify the index every time you want to loop over an array (the condition of the loop must be in function of arrSize). Or you can if you want for this specific exemple to ignore that and focus on the logic: verify the input (in your case the input n must be: 0 <= n <= 255)
void *ieee2b(double value,char size,void *res){
char
*p0=res,
*p=p0;
vbreplacec(vbsprintf(p,"%*.*s",size,size," "),' ','0',p);
if((long)value!=value)
while(1){
double
tmp=value*2;
*p++='0'+(long)tmp;
if(tmp==1||tmp==0||p-p0>size)
break;
value=tmp-(long)tmp;
}
else{
p=p0+size-1;
while((long)value>1){
*p--='0'+((long)value%2);
value=(long)value/2;
}
*p--='0'+((long)value);
}
return res;
}
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've written a piece of code that uses a static array of size 3000.
Ordinarily, I would just use a for loop to scan in 3000 values, but it appears that I can only ever scan in a maximum of 2048 numbers. To me that seems like an issue with memory allocation, but I'm not sure.
The problem arises because I do not want a user to input the amount of numbers they intend to input. They should only input whatever amount of numbers they want, terminate the scan by inputting 0, after which the program does its work. (Otherwise I would just use malloc.)
The code is a fairly simple number occurrence counter, found below:
int main(int argc, char **argv)
{
int c;
int d;
int j = 0;
int temp;
int array[3000];
int i;
// scanning in elements to array (have just used 3000 because no explicit value for the length of the sequence is included)
for (i = 0; i < 3000; i++)
{
scanf("%d", &array[i]);
if (array[i] == 0)
{
break;
}
}
// sorting
for(c = 0; c < i-1; c++) {
for(d = 0; d < i-c-1; d++) {
if(array[d] > array[d+1]) {
temp = array[d]; // swaps
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
int arrayLength = i + 1; // saving current 'i' value to use as 'n' value before reset
for(i = 0; i < arrayLength; i = j)
{
int numToCount = array[i];
int occurrence = 1; // if a number has been found the occurence is at least 1
for(j = i+1; j < arrayLength; j++) // new loops starts at current position in array +1 to check for duplicates
{
if(array[j] != numToCount) // prints immediately after finding out how many occurences there are, else adds another
{
printf("%d: %d\n", numToCount, occurrence);
break; // this break keeps 'j' at whatever value is NOT the numToCount, thus making the 'i = j' iterator restart the process at the right number
} else {
occurrence++;
}
}
}
return 0;
}
This code works perfectly for any number of inputs below 2048. An example of it not working would be inputting: 1000 1s, 1000 2s, and 1000 3s, after which the program would output:
1: 1000
2: 1000
3: 48
My question is whether there is any way to fix this so that the program will output the right amount of occurrences.
To answer your title question: The size of an array in C is limited (in theory) only by the maximum value that can be represented by a size_t variable. This is typically a 32- or 64-bit unsigned integer, so you can have (for the 32-bit case) over 4 billion elements (or much, much more in 64-bit systems).
However, what you are probably encountering in your code is a limit on the memory available to the program, where the line int array[3000]; declares an automatic variable. Space for these is generally allocated on the stack - which is a chunk of memory of limited size made available when the function (or main) is called. This memory has limited size and, in your case (assuming 32-bit, 4-byte integers), you are taking 12,000 bytes from the stack, which may cause problems.
There are two (maybe more?) ways to fix the problem. First, you could declared the array static - this would make the compiler pre-allocate the memory, so it would not need to be taken from the stack at run-time:
static int array[3000];
A second, probably better, approach would be to call malloc to allocate memory for the array; this assigns memory from the heap - which has (on almost all systems) considerably more space than the stack. It is often limited only by the available virtual memory of the operating system (many gigabytes on most modern PCs):
int *array = malloc(3000 * sizeof(int));
Also, the advantage of using malloc is that if, for some reason, there isn't enough memory available, the function will return NULL, and you can test for this.
You can access the elements of the array in the same way, using array[i] for example. Of course, you should be sure to release the memory when you've done with it, at the end of your function:
free(array);
(This will be done automatically in your case, when the program exits, but it's good coding style to get used to doing it explicitly!)
#define LEN 200
int main()
{
int arr[LEN],i;
for (i =0; i < LEN; i++)
while(scanf("%d", arr[LEN]) == 1){
if((arr[LEN] == arr[LEN]+1) || arr[LEN] < 0){
printf("Bad numbers.\n");
}
else if(arr[LEN] == 0){
break;
}
}
printf("Break");
return 0;
}
My point is if I'm writing numbers that are different and greater than 0 and arr[5] is different from a[12] or a[any other] it should save it into the array. But else if arr[LEN] == 0 it should stop scanf and save read numbers into the array and then continue with other stuff. After a few numbers, my code crashed. Can somebody help me?
Inside the for loop, you need to use arr[i] instead of arr[LEN]. Truly speaking, arr[LEN] declaration creates an array of name arr with index ranging from 0 to LEN-1. So arr[LEN] is out of range of your array.
In scanf, you need to use &arr[i] instead of arr[LEN].
In the if condition you need to write if(arr[i] == arr[i-1]) because you can compare presently input value only with previous value, not with next value which has not been entered yet. But make sure you handle this condition separately for i=0 because then i-1 will not be an element of array.
I think these changes will make your code work smoothly for all values.
Also, if you want to make sure that all array values are different then you have to compare present input value with all the previously stored values. Because current value might be different from just previous value but may be similar to value entered even before that.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to sum an array of numbers. The array has a length determined by an input and then the user gives the array. There were no compilation errors and I am able to run other programs. On the immediate start of running the program I am given a message that program has stopped working and that windows is searching for solution.
#include <stdio.h>
int main()
{
int sum, length, count;
int array[length];
sum=0;
scanf("%d",&length);
scanf("%d",&sum);
for(count=0; count<length-1; count++)
{
sum = sum + array[count];
}
printf("%d", sum);
return 0;
}
When you declare your array it depends on length but you ask the user for length after.
A solution could be to ask the user for length (scanf("%d",&length);) before declaring your actual array (int array[length];).
you should move int array[length] to after scanf("%d", &length). But it is not allowed in C to declare variables after the first non-declaration (it is however possible if you compile this program as C++).
In fact, in standard C you can't have a non-const length definition for an array variable. gcc on the other hand for example allows this nevertheless.
In your case, the problem is that length has an undefined value at the declaration of int array[length];. If you are lucky, your data segment has been initialized to zero (there is no guarantee for that) but otherwise, it may be any value, including a value which leads the program to exceed your physical memory.
A more standard way of doing this is:
int *array = NULL;
scanf("%d",&length);
...
array = (int*) malloc(sizeof(int) * length);
...
free(array);
By the way, even after fixing that, you will most likely get random numbers because you never actually assign the contents of the elements of array.
Local variable are initialized to 0. Hence value of length is 0. So you array is of length. You are then reading length, say 10, from stdin and expect the array to be of length 10. This can't be. Since this is a stack variable, the size is determined in time of pre-processing and not in run time. If you want to define the array length in run time then use malloc.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int sum, length, count;
int *array;
sum=0;
scanf("%d", &length);
scanf("%d",&sum);
array = (int *)malloc(sizeof(int) * length);
if (array == NULL) return 0;
memset(array, length, 0);
for(count=0; count<length-1; count++)
{
sum = sum + array[count];
}
printf("%d", sum);
return 0;
}
Thanks.
first problem:
the length variable is being used to set the number of entries in the array[], before the variable length is set. Therefore, length will contain what ever trash happens to be on the stack when the program starts so the number of entries defined in array[] is an unknown.
This results in undefined behaviour and could lead to a seg fault event, depending on what was on the stack and what the user entered for length.
second problem:
The array array[] is never initialized so will contain what ever trash is on the stack at program startup. This means the value being printed could be anything. And the 'sum' could overflow, depending on the trash values in array[]
OP program lacks the part of data input, it's asking for sum instead of the values to sum, which is weird. The only inputs requested are also never checked (the return value of scanf must always be checked).
In C (at least C99 and optionally C11) Variable Length Arrays, like the one defined by int array[length], can be used, but the variable length here is used uninitialized and before it is even asked to the user.
Moreover, the loop where the sum is calculated stops before the last element of the array (not really a big deal in this case, considering that all those variables are uninitialized...).
A better way to perform this task could be this:
#include <stdio.h>
// helper function to read an integer from stdin
int read_int( int *value ) {
int ret = 0;
while ( (ret = scanf("%d", value)) != 1 ) {
if ( ret == EOF ) {
printf("Error: Unexpected end of input.\n");
break;
}
scanf("%*[^\n]"); // ignore the rest of the line
printf("Please, enter a number!\n");
}
return ret;
}
int main(void) {
int sum = 0,
length = 0,
count,
i;
printf("Please, enter the number of values you want to add: ");
if ( read_int(&length) == EOF )
return -1;
// Use a VLA to store the numbers
int array[length];
// input the values
for ( count = 0; count < length; ++count ) {
// please, note ^^^^^^^^ the range check
printf("Value n° %2d: ", count + 1);
if ( read_int(&array[count]) == EOF ) {
printf("Warning: You entered only %d values out of %d.\n",
count, length);
break;
}
// you can sum the values right here, without using an array...
}
// sum the values in the array
for ( i = 0; i < count; ++i ) {
// ^^^^^^^^^ sum only the inputted values
sum += array[i];
}
printf("The sum of the values is:\n%d\n", sum);
return 0;
}
Is it possible to decrement the array size in a while loop in C by more than x--. For example, can you decrement an array by a third of the array size with each iteration?
int n = 10;
while (n < 0)
// do something
(round(n/3))-- // this doesn't work, but can this idea be expressed in C?
Thank you for the help!
You can use any expression:
int n = 10;
while (n > 0) // Note change compared with original!
{
// Do something
n = round(n/3.0) - 1; // Note assignment and floating point
}
Note that you can only decrement variables, not expressions.
You could also use a for loop:
for (int n = 10; n > 0; n = round(n/3.0) - 1)
{
// Do something
}
In this case, the sequence of values for n will be the same (n = 10, 2) whether you round using floating point or not, so you could write:
n = n / 3 - 1;
and you'd see the same results. For other upper limits, the sequence would change (n = 11, 3). Both techniques are fine, but you need to be sure you know what you want, that's all.
Yes, it is possible to add or subtract any number to your variable n.
Usually, if you want to do something a very predictable number of times, you would use a for loop; when you aren't sure how many times something will happen, but rather you are testing some sort of condition, you use a while loop.
The rarest loop is a do / while loop, which is only used when you want to execute a loop one time for certain before the first time the while check occurs.
Examples:
// do something ten times
for (i = 0; i < 10; ++i)
do_something();
// do something as long as user holds down button
while (button_is_pressed())
do_something();
// play a game, then find out if user wants to play again
do
{
char answer;
play_game();
printf("Do you want to play again? Answer 'y' to play again, anything else to exit. ");
answer = getchar();
} while (answer == 'y' || answer == 'Y');
There is no array in your code. If you wan't n to have a third of its value on each iteration, you can do n /= 3;. Note that since n is integral then the integral division is applied.
Just like K-Ballo said there is no array in your example code but here is an example with an integer array.
int n = 10;
int array[10];
int result;
// Fill up the array with some values
for (i=0;i<n;i++)
array[i] = i+n;
while(n > 0)
{
// Do something with array
n -= sizeof(array)/3;
}
But be careful in the example code you gave the while loop is checking if n is less than zero. As n is intialised to 10 the while loop will never be executed. I have changed it in my example.