local and global arrays and segmentation fault - arrays

I'm having trouble with the following: I want to take a large number (cca. 15-digit) and turn it into individual digits and store them in an array. I will need these digits further on in the code. The problem is, if I declare the array outside the while loop, it stores the first four values, but then I get a segmentation fault. If I declare it within the loop, the code works as I want it to, but then I don't know how to move the array out of that loop, so that I could use it further. How can I solve this? This is what I've compiled:
unsigned long long card_num;
printf("Enter your credit card number:\n");
scanf("%llu", &card_num);
int count = 0;
while (card_num != 0)
{
int digits[count]; //declaring array into which digits will be stored
digits[count] = card_num%10; // get last digit, store it in array
card_num = card_num/10; //remove last digit
printf("Digit[%i] = %i\n", count, digits[count]);
printf("Number of digits: %i\n", count);
count ++;
}

In your code, for the very first iteration
int digits[count];
count is 0, which violates the constraints mentioned in spec. As per C11, chapter 6.7.5.2,
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. [....]
and
If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *; otherwise, each time it is evaluated it shall have a value greater than zero
So, this is not a valid code.

As already mentioned, what you are doing is plain wrong.
There is several ways to solve this issue. The easiest would be to allocate an array at the beginning of your program with enough space for all your usecases with something like :
#define MAX_DIGIT 50
int digits[MAX_DIGIT];
Then you just have to check you are not going over this array by checking that count < MAX_DIGIT.
Another way would be using dynamic memory allocation using an int pointer int *digits and malloc (I let you google that) once you know the size of the array you'll need. You'll have to change a bit your code to know the number of digits before starting to get the digits as you need to allocate the memory before starting to store digits.
You could use realloc to keep a code similar to what you already have, but I wouldn't advise it as it is not efficient to realloc memory for each value that you add.

Your logic is fine.
What went wrong is that you tried to increase the length of a fixed-length array while iterating which is not allowed.
You should never change the length of a fixed-length array anywhere in the program.
However if you want to change the length of an array during runtime you must use the malloc and realloc functions to do so.
Check out this example:
//declarations
int *storeNum;
storeNum = (int *)malloc(1 * sizeof(int));
//logic
while(num != 0) {
if(i > 0)
storeNum = realloc(storeNum, (i+1) * sizeof(int));
storeNum[i] = num % 10;
num = num/10;
++i;
}
Here first I declared the array size initially as one and later incremented it using realloc function.
You also have the array size stored in i which you can use later in your code in loops.
But keep in mind that the digits will be stored in your array in reverse order.
Also, you shouldn't declare an array within a loop.
Since you have "declared" the array, each time the compiler enters the loop while iterating it will consider the array-declaration as a new array. That is all.

Related

How do I find the number of element of an array which have their size previously undefined

I'm trying to make an array which have it's element coming from a user input. This array would first have it's size undefined since we don't know how much int would the user input, but then I'm not able to find the amount of element in the array like this unless I put a counter on the loop function.
Here is the code that I've made:
int cross[] = {0};
int k;
for (k = 0; k >= 0; k++){
scanf("%d", &cross[k]);
if (cross[k] == -1){
break; //stop the user from inputing numbers if user input -1
}
int p = sizeof(cross) / sizeof(cross[0]);
If I were to do printf("%d", p), it would always give me 1 as a result. I'm wondering if there is any other way of doing this other than putting a counter on the for loop.
Thanks!!
This phrase from your question is both wrong and dangerous: "This array would first have it's size undefined".
The following line of code defines a fixed-size array that has exactly one element:
int cross[] = {0};
The compiler knows it's one element because you supplied one initializer value {0}. If you supplied this {0, 5, 2}, it would allocate 3 integers, and so on.
This means when you store into cross[k] and k is larger than zero, you're actually exceeding the bounds of your allocated array, which C doesn't catch at compile time, but could cause nasty problems at run time.

digit to integer in same order C [closed]

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 5 years ago.
Improve this question
I have a function called fun(int num, int * array); which takes an int and int array as its arugments. I'm trying to convert int to the array.
When i run the program i don't get the array displayed properly
int fun(int num, int*array) {
int count =0;
while(num>0) {
num/= 10;
count++;
}
array[count];
// for loop works
}
When i print the array in the program i.e. everytime I run the program i get random digits.
What this line is supposed to do ?
array[count];
Since your integer array will change in your fun function, you have to allocate the memory (by using malloc, realloc, ...).
edit : plus, you already change the value hold by "num" when you count how many digit there are in "num".
Make a copy of "num" !
edit 2 : the more i look your function, the more it seem you will have problem using it.
Fisrt, you want to explode your integer into an array of int.
Okay, but integer have range, thus meaning integer have a maximum digit.
From my memories, there are 20 digit in an 64bit integer.
So you can simply use "int array[NB_DIGIT_INT_MAX];" with "#define NB_DIGIT_INT_MAX 21".
So, allocating is not necessary AND add complexity in your code (the caller will have to free after the function call).
Second, your fun function doesn't say how many case will hold your integer.
Let's say num = 12, your array will have "array[0] = 1, array[1] = 2", but how do you know where to stop ?
If num = 2345, how do you know that only the 4 first case in your array is legit ?
There are 2 way : You have an another variable that hold the actual size of the array, or you have a special value in your array that say "it's the end" (like '\0' for char array used as string).
You can use "-1".
Let's give a try, and don't hesitate to ask question if thing are unclear (english is not my motherlanguage)
Your array is not even allocated, this can not work as expected. You are even lucky not to have a segmentation fault. If you want to add an integer to an array making it grow, you need to allocate a larger array, copy the values and add the new one to the new array and delete the previous array, keeping array variable as a pointer to the new array. Moreover, you need to pass the size of the actual array as an argument of fun.
The count variable can be global, Initialize it outside all functions like this
short count;
The whole program could be modified like below
#include<stdio.h>
#include<stdlib.h>
short count;
void fun(int num, int **ptr) {
// You need a pointer to a pointer and return type can be void
int num_copy=num;
count=0; // Setting the count to zero
while(num_copy>0) {
num_copy/= 10; // Don't modify the original number
count++;
}
//Allocate enough memory to store the digits
*ptr=malloc(count*sizeof **ptr);
if(NULL==*ptr){
perror("Can't allocate memory");
exit(1);
}
// Then do the loop part with original num
for(int i=count -1; i>=0; i--) {
(*ptr)[i] = num%10;
num /= 10;
}
// By now you have an array 'array' of integers which you could print in main.
}
int main()
{
int number = 123456789;
int *array;
fun(number,&array); // &array is of type pointer to a pointer to integers
//Now print the individual digits
printf("Individual digits are : \n");
for(int i=count-1;i>=0;i--)
printf("%d\n",array[i]);
}
Looks to me like you are converting from an integer to digits. But I don't see where your code writes anything to the array.
If the array wasn't initialized before this, that would explain why it still contains random values.

Code to change an array element changes a different variable

I'm quite puzzled by why my variable NumberOfArrays changes the second time through the for loop in my code. Can anyone help me out?
#include <stdio.h>
#include <cs50.h>
int main(int argc, string argv[])
{
//variable declarations
int NumberOfArrays = 0;
int arrayRack[0];
//Get number of arrays
printf("Key in the number of arrays you'd like to have\n");
NumberOfArrays = GetInt();
//Get number for each element in arrayRack[]
for(int i = 0; i < NumberOfArrays; i++)
{
printf("give me an int for the %i th array\n", i + 1);
arrayRack[i] = GetInt();
// *** on the second pass, my "NumberOfArrays" gets adjusted to my GetInt number here. Why?
}
//print out numbers stored in respective arrays
for(int j = 0; j < NumberOfArrays; j++)
{
printf("{%i}<-- number in %ith array\n", arrayRack[j], j + 1);
}
return 0;
}
Because you declared arrayRack as an empty array ([0]). Try int arrayRack[100]; or some other number, and make sure that NumberOfArrays is less than that number before you use it.
Explanation: (edit note that this may vary by compiler) your variables are most likely stored on the stack in nearby memory addresses. So arrayRack points somewhere close to NumberOfArrays in memory. C doesn't generally check if you've run off the end of an array, so accessing arrayRack[1] doesn't cause a compiler error in this situation. However, arrayRack[1] isn't part of your array, so accessing it actually accesses something else — in this situation, NumberOfArrays.
Edit gcc permits length-0 arrays but does not allocate space for them per this. However, length-0 arrays are prohibited by the C standard (e.g., see this, the answers to this, and this). Given the behaviour you've seen, it looks to me like the compiler is allocating one int's worth of space on the stack, pointing arrayRack to that space, and packing that space right next to NumberOfArrays. As a result, &(arrayRack[1]) == &NumberOfArrays. In any event, using variable-length arrays as suggested by #dasblinkenlight is a cleaner way to handle this situation.
In general, given int arrayRack[N];, you can only safely access arrayRack[0] through arrayRack[N-1].
You declared the array too early. Move the declaration to after the call of GetInt(), like this:
printf("Key in the number of arrays you'd like to have\n");
int NumberOfArrays = GetInt();
int arrayRack[NumberOfArrays];
Note: NumberOfArrays is not an ideal name for the variable, because it denotes the number of array elements, not the number of arrays; your code has only one array.

Passing a 2d-array to a function in C

Note I'm using C not C++. I'm working on a program that will take a 2d-array and count the numbers of non-spaces in a subarray. Such as lines[0][i] <-- iterating over line[0][0] - line[0][n]. However, I'm having difficulty getting the function to accept the 2d-array.
Here is my code:
pScore[0]=letters(pLines, 0);
This is the actual function. pScore[] is another array, but a 1d one. pLines is a 4 by 200 2d-array.
int letters(char line[][], int row)
{
int i = 0;
int n = n;
int results = 0;
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
{
if( !isspace(line[row][i]) )
results++;
}
return results;
}
When I do this it gives me "formal parameter number 1 is not complete". If I remove the second [] from it, the code runs but gives the worng number of non-space characters.
Taking from the comments above, and your function parameter list:
int letters(char line[][], int row)
You violate one primary tenant of passing a 2D array to a function. Specifically, you must always provide the number of columns contained in the array. e.g.
int letters(char line[][5], int row)
char line[][5] is an appropriate parameter. However, whenever you pass an array as a function parameter, the first level of indirection is converted to a pointer. (you will often here this referred to as "pointer-decay", though that is a bit of a misnomer). Therefore a proper declaration that makes this clear is:
int letters(char (*line)[5], int row)
line, after conversion, is a pointer-to-an-array of 5-int. While you can pass the array as line[][5], that is not nearly as informative as (*line)[5]. Let me know if you have any questions.
Numbers Instead of Characters
It is hard to tell what is going on without seeing the remainder of your code. However, I suspect that you are confusing the numerical value and the ASCII character value for the contents of your array. (e.g. character '0' = decimal 48 (0x30 (hex), '1' = 49, 'a' = 97, etc..). See ASCIItable.com
You you pass an array to a function it decays to a pointer. That means char line[][] should really by char (*line)[SIZE_OF_SECOND_ARRAY].
It also means the sizeof trick will not work, as doing sizeof on the pointer line will just return the size of the pointer and not what it points to, you need to explicitly pass the size as an argument to the function.
You need tell function the number of columns of 2d array. Here may help you.
I am not sure if the following statement works with you
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
where sizeof(line) will be 4 or something like that depends on your platform because "line" is a pointer and you get the size of pointer itself.
Correct me if I am wrong.
In this case, you should pass column number as row's.

Algorithm for processing the string

I really don't know how to implement this function:
The function should take a pointer to an integer, a pointer to an array of strings, and a string for processing. The function should write to array all variations of exchange 'ch' combination to '#' symbol and change the integer to the size of this array. Here is an example of processing:
choker => {"choker","#oker"}
chocho => {"chocho","#ocho","cho#o","#o#o"}
chachacha => {"chachacha","#achacha","cha#acha","chacha#a","#a#acha","cha#a#a","#acha#a","#a#a#a"}
I am writing this in C standard 99. So this is sketch:
int n;
char **arr;
char *string = "chacha";
func(&n,&arr,string);
And function sketch:
int func(int *n,char ***arr, char *string) {
}
So I think I need to create another function, which counts the number of 'ch' combinations and allocates memory for this one. I'll be glad to hear any ideas about this algorithm.
You can count the number of combinations pretty easily:
char * tmp = string;
int i;
for(i = 0; *tmp != '\0'; i++){
if(!(tmp = strstr(tmp, "ch")))
break;
tmp += 2; // Skip past the 2 characters "ch"
}
// i contains the number of times ch appears in the string.
int num_combinations = 1 << i;
// num_combinations contains the number of combinations. Since this is 2 to the power of the number of occurrences of "ch"
First, I'd create a helper function, e.g. countChs that would just iterate over the string and return the number of 'ch'-s. That should be easy, as no string overlapping is involved.
When you have the number of occurences, you need to allocate space for 2^count strings, with each string (apart from the original one) of length strlen(original) - 1. You also alter your n variable to be equal to that 2^count.
After you have your space allocated, just iterate over all indices in your new table and fill them with copies of the original string (strcpy() or strncpy() to copy), then replace 'ch' with '#' in them (there are loads of ready snippets online, just look for "C string replace").
Finally make your arr pointer point to the new table. Be careful though - if it pointed to some other data before, you should think about freeing it or you'll end up having memory leaks.
If you would like to have all variations of replaced string, array size will have 2^n elements. Where n - number of "ch" substrings. So, calculating this will be:
int i = 0;
int n = 0;
while(string[i] != '\0')
{
if(string[i] == 'c' && string[i + 1] == 'h')
n++;
i++;
}
Then we can use binary representation of number. Let's note that incrementing integer from 0 to 2^n, the binary representation of i-th number will tell us, which "ch" occurrence to change. So:
for(long long unsigned int i = 0; i < (1 << n); i++)
{
long long unsigned int number = i;
int k = 0;
while(number > 0)
{
if(number % 2 == 1)
// Replace k-th occurence of "ch"
number /= 2;
k++;
}
// Add replaced string to array
}
This code check every bit in binary representation of number and changes k-th occurrence if k-th bit is 1. Changing k-th "ch" is pretty easy, and I leave it for you.
This code is useful only for 64 or less occurrences, because unsigned long long int can hold only 2^64 values.
There are two sub-problems that you need to solve for your original problem:
allocating space for the array of variations
calculating the variations
For the first problem, you need to find the mathematical function f that takes the number of "ch" occurrences in the input string and returns the number of total variations.
Based on your examples: f(1) = 1, f(2) = 4 and f(3) = 8. This should give you a good idea of where to start, but it is important to prove that your function is correct. Induction is a good way to make that proof.
Since your replace process ensures that the results have either the same of a lower length than the original you can allocate space for each individual result equal to the length of original.
As for the second problem, the simplest way is to use recursion, like in the example provided by nightlytrails.
You'll need another function which take the array you allocated for the results, a count of results, the current state of the string and an index in the current string.
When called, if there are no further occurrences of "ch" beyond the index then you save the result in the array at position count and increment count (so the next time you don't overwrite the previous result).
If there are any "ch" beyond index then call this function twice (the recurrence part). One of the calls uses a copy of the current string and only increments the index to just beyond the "ch". The other call uses a copy of the current string with the "ch" replaced by "#" and increments the index to beyond the "#".
Make sure there are no memory leaks. No malloc without a matching free.
After you make this solution work you might notice that it plays loose with memory. It is using more than it should. Improving the algorithm is an exercise for the reader.

Resources