So I'm a beginner with C programming and understanding pointers and how to use them is still giving me some trouble. Here I'm simply trying to iterate through an array using a pointer. I've got this bit of code below but instead of ending at 55, it prints an additional value (32765). First, could someone explain to me why I'm getting an extra value? Second, could someone tell me how to limit this program to the values in the array? I tried using *pntr < 5 for the condition but then nothing prints.
void iterate(int* li) {
for (int *pntr = li; *pntr; pntr++) {
printf("%d\n", *pntr);
}
}
int main(){
int values[] = {11, 22, 33, 44, 55};
iterate(values);
}
This is the right code
void walk(const int *arr, size_t n)
{
int *p;
for (p = arr; p < arr + n; ++p)
printf("%d\n", *p);
}
This is because arr + n gets the address of n integers from the base address of arr.
In addition, int arrays aren't null terminated; only char arrays are when they are used with quotation marks.("abc" rather than {'a', 'b', 'c'}).
This for loop:
for (int *pntr = li; *pntr; pntr++) {
printf("%d\n", *pntr);
}
...expects the array to be zero-terminated. By using *pntr as your test, you're testing that the value pointed to by pntr is not zero. As such, if the array doesn't end with a zero, your loop will wander off past the end of the array until it happens to hit a zero or causes a segfault.
your code is overall not bad, but it's missing one major factor: a working end condition.
In your for loop, when you write *pntr, the end condition will be that the loop will halt when reaching a pointed value of 0. But as your array contains non-zero values, it will get one beyond the allocated memory for your array.
Luckily for you, you only see one extra value, but you might see a lot more values.
To fix the missing end conditions, you have two solutions: either you share the array's length with your iterate function, or you add a value that's known to be the final value of your array.
So either you do:
void iterate(const int *arr, size_t n) {
for (it = arr; it < arr+n ; +=it) printf("$d\n", *it);
}
or you can do:
#define LAST_ITEM -1
int values[] = {11, 22, 33, 44, 55, LAST_ITEM};
void iterate(const int *arr, size_t n) {
for (it = arr; *it != LAST_ITEM ; +=it) printf("$d\n", *it);
}
(you could use #define LAST_ITEM 0, as long as you use a value that's not likely to happen in your array).
Out of these two solutions, the best one is to consider your array with its size.
Related
I was trying to make a code to find duplicates in an array and print them. I can't understand this code and why the Calloc is being used and the int main part isn't clear to me.
#include<stdio.h>
#include<stdlib.h>
void printRepeating(int arr[], int size)
{
int *count = (int *)calloc(sizeof(int), (size - 2));
int i;
printf(" Repeating elements are ");
for(i = 0; i < size; i++)
{
if(count[arr[i]] == 1)
printf(" %d ", arr[i]);
else
count[arr[i]]++;
}
}
int main()
{
int arr[] = {4, 2, 4, 5, 2, 3, 1};
int arr_size = sizeof(arr)/sizeof(arr[0]);
printRepeating(arr, arr_size);
getchar();
return 0;
}
The code is actually "dangerous", as it relies on some conditions to hold, e.g. that the maximum integer value in the array is not larger than size-2. So, if your input were, for example, int arr[] = { 114, 112, 114, 5, 2, 3, 1}, then arr[0] would be 114, and the code count[arr[0]]++ would exceed the bounds of the array allocated in printRepeating, which were just 5 elements.
I'd throw the code away and write your own; almost regardless on your experience, your code is likely not worse than the proposed one :-)
The reason for using calloc is that the size isn't known in advance. An alternative would be to use VLA but apparently the author preferred dynamic memory allocation. Kind of bad as the author forgot to free the memory. So this code leaks memory.
Besides that the code is very error prone as it relies on some specific rules for the input (e.g. that no input value is greater that size-2). So my advice is to through this code away and start all over.
BTW: The code uses calloc instead of malloc to get the memory zero initialized.
Regarding main.... This line:
int arr_size = sizeof(arr)/sizeof(arr[0]);
calculates the number of elements in the array.
sizeof(arr) is likely to return 28
sizeof(arr[0]) is likely to return 4
So
28/4 = 7 which is the number of array elements.
This code is really wrong, you shouldn't use it at all.
To give you some hints, this line creates an array:
int *count = (int *)calloc(sizeof(int), (size - 2));
Similar to:
int count[size - 2] // If size was a constant
An unfortunate issue is that the function never disposes the dynamically created array, so you'll see a memory leak.
Line count[arr[i]]++ is a disaster: if the value of arr[i] is greater than size-2 then the software will write to an unassigned memory.
To show how it should be done:
// No value should exceed 50
#define MAX_ARR 50
void printRepeating(int arr[], int size)
{
int found[MAX_ARR];
int i;
// Set found variable to 0
memset(found, 0, sizeof(found));
for(i = 0; i < size; i++)
{
// Did we find the same number before?
if (found[arr[i]] == 1) {
// Yes, print it
printf(" %d ", arr[i]);
} else {
// No, mark is as found
found[arr[i]] = 1;
}
}
}
Actually we use malloc( ) for allocating a single block of specified size that returns a pointer of type of void. This means that we can assign it to any type of type. Form is:
ptr = ( cast - type*) malloc(byte-size)
One very significant difference in malloc() and calloc() is :
While malloc() allocates a single block of storage space with garbage (or random) values, calloc() allocates allocates multiple blocks of storage, each of the same size, and then sets all bytes to zero.
Based on This Question Calculate Length of Array in C by Using Function i really need an explanation.
Let's say we have an Array like this:
int arr[] = {1,2,3};
here arr has the length 3, so passing into a Function will decay to Pointer and we lose track of its Length.
What happens if we Null terminate this array using '\0' like this:
int arr[] = {1,2,3,'\0'};
And pass it to a function like this:
void foo(int *arr){
int length = 0;
while(arr[length] != '\0'){
length++;
}
printf("Length = %d\n",length);
}
Is this ok?
I wrote the following code:
#include<stdio.h>
void foo(int *arr);
int main(void){
int arr1[] = {10,'\0'};
int arr2[] = {12,44,'\0'};
int arr3[] = {87,1,71,'\0'};
int arr4[] = {120,15,31,82,'\0'};
int arr5[] = {28,49,16,33,11,'\0'};
int arr6[] = {19,184,90,52,38,77,'\0'};
int arr7[] = {2,17,23,41,61,78,104,'\0'};
int arr8[] = {16,92,11,35,52,118,79,44,'\0'};
int arr9[] = {20,44,33,75,49,36,9,2,11,'\0'};
int arr10[] = {92,145,24,61,99,145,172,255,300,10,'\0'};
foo(arr1);
foo(arr2);
foo(arr3);
foo(arr4);
foo(arr5);
foo(arr6);
foo(arr7);
foo(arr8);
foo(arr9);
foo(arr10);
return 0;
}
void foo(int *arr){
int length = 0;
while(arr[length] != '\0'){
length++;
}
printf("Length = %d\n",length);
}
And i got the following Output:
Length = 1
Length = 2
Length = 3
Length = 4
Length = 5
Length = 6
Length = 7
Length = 8
Length = 9
Length = 10
Which prints the Length of all 10 arrays.
Now I'm confused here, because as far of my concern, as I read in some books, there is no way to make it work.
Why foo prints the length of all arrays?
It is illegal to use something like int arr[] = {1,2,3,'\0'}; ?
I know that if the Array has a 0 inside like this int arr[] = {1,2,0,3,4}; the length will be 2, but this is not my question.
This is how C-strings mark their end and length. And as they're just char arrays, naturally you can apply the same to other types of arrays as well.
Just remember that calculating the length of such an array through a pointer has a linear time complexity.
It is illegal to use something like int arr[] = {1,2,3,'\0'}; ?
No. It's perfectly legal. '\0' is an int which is same as 0. It's no different to using any number as marker to identify the end of the array. For example, you can use -1 if you array is going to contain only positive number. So your approach is valid.
The reason you wouldn't usually see in practice it's kind of needless to iterate over an array when you can simply pass it as an extra argument, which is easily understandable from maintenance point of view.
int arr[1024];
size_t len = sizeof arr/sizeof a[0];
func(arr, len);
void func(int *a, size_t length) {
}
Compare this with your approach.
Also, the size is calculated at compile-time whereas in your approach you have iterate over the array. Choosing the right sentinel could become difficult ( o or -1 or whatever) if it's also needed to be an element of the array.
Sidenote: '\0' is really 0 here, as your store ints.
You're using a sentinel. C-style strings have been using this method for decades to mark where the string finishes. It has the same benefits, but it also has the same drawbacks.
As long as you maintain the invariant that the sentinel occours only at the last place of the array you'll be able to get the length of the array. In O(N) time, as you have to traverse the sequence.
Note that you can shrink the sequence by terminating it earlier with a sentinel:
1 2 3 4 0 //
1 2 3 0 * // * as in: anything
But as soon as you do this, you cannot known the size of the array anymore. Even though you could technically append an extra element, a function without knowing the context cannot safely do this. In essence, you know the size of the sequence, but you don't known the size of the array anymore.
If you need a method to use to allow you to carry the array length with the array then try using one of these approaches.
Store the length in the start of the array
So (ideally) array[0], the first element would be a length.
The catch is that that only works if your array has a suitable type and the length fit in that type. You can in principle use union to define an element large enough to hold different types of data, including the length, but it's potentially wasteful.
Maintain a structure to store the array length and a pointer to the array data.
This is something like :
struct arrayinfo_s {
int length ;
char *data ;
};
char name[1000] ;
struct arrayinfo a ;
a.length = sizeof(name) ;
a.data = name ;
myfunc( &arrayinfo ) ;
There are many variations on this possible.
The "standard" convention.
As someone already mentioned, it is typical to track the array length and pass it as a separate parameter to the function.
myfunc( array, length ) ;
If array is a fixed size declared like e.g. int nums[100] ; then you can use sizeof(nums) if the variable was declared in the same function as you used sizeof() or globally.
There is also a variation on this for allowing a function to return an array of unknown length. Typically you would do something like returning a point to the array, but pass a parameter that is a pointer to some integer type to store the length of the new array in.
char *newstuff( int *newlength )
{
char *p = NULL ;
p = malloc( 102 ) ;
if( p == NULL )
{
*length = 102 ;
return p ;
}
else
{
*length = 0 ;
return NULL ;
}
}
I have a c function that produces my a int array using malloc. It works quiet well and I think it isn't really important what it does because the problem doesn't really have anything to do with that. (In this case it calculates the numbers to a given int and base). I need this array temporary in a function, which might be a sub function of a sub function of a ... (you got the idea, point this function can be used several times) and before the return I would like to run free, but it doesn't work. Here is a testing code (it sorts an array of ints to the amount of ones in their binary representation using qsort (yes I know could have calculated the results more directly, but the point is the probleme I run into when trying to run free (here comment out in function ones))):
#include <stdio.h>
#include <stdlib.h>
int values[] = { 88, 56, 100, 2, 25, 0, 15};
int * baseString(int u, int base);
int abs(int a);
int ones(int a);
int cmpfunc (const void * a, const void * b)
{
return ones(*(int*)a)>ones(*(int*)b);
}
int main()
{
int n;
printf("Before sorting the list is: \n");
for( n = 0 ; n < 7; n++ )
{
printf("%d ", values[n]);
}
qsort(values, 7, sizeof(int), cmpfunc);
printf("\nAfter sorting the list is: \n");
for( n = 0 ; n < 7; n++ )
{
printf("%d (Ones=%d) ", values[n], ones(values[n]));
}
printf("\n");
return(0);
}
int abs(int a){
return (a<0)? a*-1:a;
}
int* baseString(int u, int base){
int* r=malloc(sizeof(int));
r[0]=base;
r[1]=1;
if(base<2){
r[2]=-1;
return r;
}
int negativ=0;
if(u<0){
u=abs(u);
negativ=1;
}
int i=2;
do{
int ur=u%base;
r[i]=ur;
u/=base;
i++;
}while(u>0);
r[1]=i-1;
if(negativ){
r[1]=-r[1];
}
return r;
}
int ones(int a){
int* ai=baseString(a, 2);
int a1=1;
for(int i=2; i<abs(ai[1]); i++){
if(ai[i]==1){
a1++;
}
}
if(!a){
a1=0;
}
//free(ai);
return a1;
}
PS: I am quiet sure this thread is duplicate of some tread somewhere, but I didn't found it.
Part of your problem is actually quite simple.
In your baseString() function, the first three lines are
int* r=malloc(sizeof(int));
r[0]=base;
r[1]=1;
The malloc() dynamically allocates a single int, or an array with one element. The r[1] = 1 modifies the second element of that array which has one element.
The result of that is undefined behaviour. A common symptom of running off the end of an array like this is corrupting memory in your program, such as that used internally by malloc() and free() to keep track of allocated and released memory. Which would explain your problem.
Make sure you allocate the number of elements needed. For example, if 10 elements are needed, malloc(10*sizeof(int)). You need to work out the number needed, since dynamically arrays will not magically grow to get the number of elements needed.
I haven't look further, so there may be other problems. But this one is pretty glaring.
It is also a good idea to check that malloc() actually succeeds. It returns NULL if it fails.
The key problem here appears to an ABW (Array Bounds Write). In the baseString function, you are actually allocating memory which is equivalent to the size of 1 integer, but are trying to access it like an array in r[1],r[2], r[i] etc, which results in write to memory which technically doesn't belong to you.
The code snippet in your code corresponds to
int* r=malloc(sizeof(int));
r[0]=base;
r[1]=1; //ABW here
if(base<2){
r[2]=-1; //ABW here
return r;
}
do{
int ur=u%base;
r[i]=ur; //ABW here
u/=base;
i++;
}while(u>0);
This might lead to undefined behavior at any point of time in your code. In your case, it seems to be affecting free as the memory overwrite may have messed up with the internal book keeping data of malloc and free implementation.
I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)
Suppose I have this logical array with, which I want to split into the 1 part and the 0 part, creating two separate vectors.
So I came up with the following method:
void cut_and_uncut(long* input, int length, long* cut_part, int* cut_length, long* uncut_part, int* uncut_length){
int i;
int n_cut=0;
for(i=0;i<length;i++) n_cut+=input[i];
cut_part = vecallocl(n_cut);
uncut_part = vecallocl(length-n_cut);
*cut_length = n_cut;
*uncut_length = length-n_cut;
int index_cut = 0;
int index_uncut = 0;
for(i=0;i<length;i++){
if(input[i]==1){
cut_part[index_cut] = i;
index_cut++;
} else {
uncut_part[index_uncut] = i;
index_uncut++;
}
}
}
input is the input vector of length length (so imaginative!)
cut_part is the vector with the indices of the 1s, of length cut_length
uncut_part is the vector with the indices of the 0s, of length uncut_length
(Note: vecallocl(k) is just a shortcut for malloc(k*sizeof(long)) )
I call this function with
int len,len2;
long* cut_vec;
long* uncut_vec;
cut_and_uncut(split,matrix.m+matrix.n,cut_vec,&len,uncut_vec,&len2);
The two ints (len and len2) are correctly filled, but when I try to look into the cut_vec and uncut_vec vectors, segfault happens.
I have the hunch that I am doing something wrong with the memory, because I initialize the two pointers without them actually pointing to anything.. but then in the function, with the actual vecallocl, they should be initialized correctly.
When I print the vectors from inside this cut_and_uncut function, everything works.. when doing it outside (i.e. at the same level this function is called) it does not.
What's wrong?
Try this:
void cut_and_uncut(long* input, int length, long** cut_part,
int* cut_length, long** uncut_part, int* uncut_length)
....
// inside the function you now use `*cut_part` instead of `cut_part`, etc.
if(input[i]==1){
*cut_part[index_cut] = i;
index_cut++;
} else {
*uncut_part[index_uncut] = i;
index_uncut++;
}
and pass not the (still unallocated) pointers but the address where they reside:
long *cut_part;
long *uncut_part;
cut_and_uncut(... &cut_part, &uncut_part, ...)
This way, modifications will be retained after cut_and_uncut() returns.