so I am a beginner in c, and I am doing this program where a user input values in an array and if the value is 101 then the program is finished. the thing is I don't want the length of the array to be initialized, rather when the user enter 101 there would be the last value and the last place in the array. for example they entered 101 in the third place then the length of the array would be 4. I don't know if that possible.
#include <stdio.h>
int main(void) {
int i,j;
int a[i];
for(i=0;i<10;i++)
{
printf("Enter Value Nummber %d:",i);
scanf("%d",&a[i]);
if
(a[i] == 101) break;
else continue;
}
Here I put the max length could be 10 but, if the user for example gives just 4 values and then 101 then it gives the rest of spots garbage values.
In this case
int a[i];
is called a variable length array, and you're using i unitialized, and that can invoke undefined behaviour. You need to have a defined value of i before you can use it.
That said, the cleaner approach will be (without using dynamic allocation and re-sizing)
Define a higher limit (#define MAXLEN 100) and use that to create an array, and initialize it to a value (say, 0).
Keep on asking user for the inputs, until (whichever is earlier)
You get a value 101
Counter reaches MAXLEN
Otherwise, if you're okay with using allocated memory (malloc()/ realloc() and family), then:
Define a starting size (#define INITSIZ 32)
Allocate memory for that size using malloc().
Ask user for inputs.
If you get an input value of 101, free() the allocated memory and exit.
Otherwise, once you hit the size, double the allocation using realloc() and continue to previous step.
I recommend having a look at malloc. It allows you to dynamically allocate memory and gives you a pointer to the start of the allocated piece of memory.
You can access an element with a pointer that points to the first element and then increase the pointer every time you add a value. Unlike other languages, C does not prevent you from accessing values outside of an array, so track the number of items added with a counter, and make sure to stay within your allocated memory (so save the length in a variable). You can then replace the for loop with an infinite loop, and break once the user inputs the value 101. When you reach the limit of your allocated memory, you can allocate a new array twice the size (so make sure to save the length in a variable) and copy the previous array there, then free the first array.
"Can I have an array with indeterminate length?"
I don't want the length of the array to be initialized, rather when the user enter 101 there would be the last value and the last place in the array. For example they entered 101 in the third place then the length of the array would be 4. I don't know if that possible.
No, it is not possible.
int a[i];
You cannot write to an indeterminate array, as i is not initialized - it holds a garbage value.
Any such attempt is undefined behavior and doesn´t make much sense.
How do you want to store the value the user puts in to the assumed third element if there has not been space allocated for it?
Of course you can use VLAs or allocate and reallocate dynamic memory (as the other two answers suggest) but you can´t write data to memory which isn´t allocated for storing that values.
I do not understand your idea behind. Maybe you explain the bigger goal you want to achieve.
Related
I have a problem, and I cannot figure out the solution for it. I have to programm some code to a µC, but I am not familiar with it.
I have to create an analysis and show the results of it on the screen of the machine. The analysis is allready done and functional. But getting the results from the analysis to the screen is my problem.
I have to store all results in a global array. Since the stack is really limited on the machine, I have to bring it to the larger heap. The linker is made that way, that every dynamic allocation ends up on the heap. But this is done in C so I cannot use "new". But everything allocated with malloc ends up on the heap automatically and that is why I need to use malloc, but I haven't used that before, so I have real trouble with it. The problem with the screen is, it accepts only char arrays.
In summaray: I have to create a global 2D char array holding the results of up to 100 positions and I have to allocate the memory for it using malloc.
To make it even more complicated I have to declare the variable with "extern" in the buffer.h file and have to implement it in the buffer.c file.
So my buffer.h line looks like this:
extern char * g_results[100][10];
In the buffer.c I am using:
g_results[0][0] = malloc ( 100 * 10 )
Each char is 1 byte, so the array should have the size of 1000 byte to hold 100 results with the length of 9 and 1 terminating /0. Right?
Now I try to store the results into this array with the help of strcpy.
I am doing this in a for loop at the end of the analysis.
for (int i = 0; i < 100, i++)
{
// Got to convert it to text 1st, since the display does not accept anything but text.
snprintf(buffer, 9, "%.2f", results[i]);
strcpy(g_results[i][0], buffer);
}
And then I iterate through the g_results_buffer on the screen and display the content. The problem is: it works perfect for the FIRST result only. Everything is as I wanted it.
But all other lines are empty. I checked the results-array, and all values are stored in them, so that is not the cause for the problem. Also, the values are not overwritten, it is really the 1st value.
I cannot see what it is the problem here.
My guesses are:
a) allocation with malloc isn't done correctly. Only allocating space for the 1st element? When I remove the [0][0] I get a compiler error: "assignment to expression with array type". But I do not know what that should mean.
b) (totally) wrong usage of the pointers. Is there a way I can declare that array as a non-pointer, but still on the heap?
I really need your help.
How do I store the results from the results-array after the 1st element into the g_results-array?
I have to store all results in a global array. Since the stack is really limited on the machine, I have to bring it to the larger heap.
A “global array“ and “the larger heap” are different things. C does not have a true global name space. It does have objects with static storage duration, for which memory is reserved for the entire execution of the program. People use the “heap” to refer to dynamically allocated memory, which is reserved from the time a program requests it (as with malloc) until the time the program releases it (as with free).
Variables declared outside of functions have file scope for their names, external or internal linkage, and static storage duration. These are different from dynamic memory. So it is not clear what memory you want: static storage duration or dynamic memory?
“Heap” is a misnomer. Properly, that word refers to a type of data structure. You can simply call it “allocated memory.” A “heap” may be used to organize pieces of memory available for allocation, but it can be used for other purposes, and the memory management routines may use other data structures.
The linker is made that way, that every dynamic allocation ends up on the heap.
The linker links object modules together. It has nothing to do with the heap.
But everything allocated with malloc ends up on the heap automatically and that is why I need to use malloc,…
When you allocate memory, it does not end up on the heap. The heap (if it is used for memory management) is where memory that has been freed is kept until it is allocated again. When you allocate memory, it is taken off of the heap.
The problem with the screen is, it accepts only char arrays.
This is unclear. Perhaps you mean there is some display device that you must communicate with by providing strings of characters.
In summaray: I have to create a global 2D char array holding the results of up to 100 positions and I have to allocate the memory for it using malloc.
That would have been useful at the beginning of your post.
So my buffer.h line looks like this:
extern char * g_results[100][10];
That declares an array of 100 arrays of 10 pointers to char *. So you will have 1,000 pointers to strings (technically 1,000 pointers to the first character of strings, but we generally speak of a pointer to the first character of a string as a pointer to the string). That is not likely what you want. If you want 100 strings of up to 10 characters each (including the terminating null byte in that 10), then a pointer to an array of 100 arrays of 10 characters would suffice. That can be declared with:
extern char (*g_results)[100][10];
However, when working with arrays, we generally just use a pointer to the first element of the array rather than a pointer to the whole array:
extern char (*g_results)[10];
In the buffer.c I am using:
g_results[0][0] = malloc ( 100 * 10 )
Each char is 1 byte, so the array should have the size of 1000 byte to hold 100 results with the length of 9 and 1 terminating /0. Right?
That space does suffice for 100 instances of 10-byte strings. It would not have worked with your original declaration of extern char * g_results[100][10];, which would need space for 1,000 pointers.
However, having changed g_results to extern char (*g_results)[10];, we must now assign the address returned by malloc to g_results, not to g_results[0][0]. We can allocate the required space with:
g_results = malloc(100 * sizeof *g_results);
Alternately, instead of allocating memory, just use static storage:
char g_results[100][10];
Now I try to store the results into this array with the help of strcpy. I am doing this in a for loop at the end of the analysis.
for (int i = 0; i < 100, i++)
{
// Got to convert it to text 1st, since the display does not accept anything but text.
snprintf(buffer, 9, "%.2f", results[i]);
strcpy(g_results[i][0], buffer);
}
There is no need to use buffer; you can send the snprintf results directly to the final memory.
Since g_results is an array of 100 arrays of 10 char, g_results[i] is an array of 10 char. When an array is used as an expression, it is automatically converted to a pointer to its first element, except when it is the operand of sizeof, the operand of unary &, or is a string literal used to initialize an array (in a definition). So you can use g_results[i] to get the address where string i should be written:
snprintf(g_results[i], sizeof g_results[i], "%.2f", results[i]);
Some notes about this:
We see use of the array both with automatic conversion and without. The argument g_results[i] is converted to &g_results[i][0]. In sizeof g_results[i], sizeof gives the size of the array, not a pointer.
The buffer length passed to snprintf does not need to be reduced by 1 for allow for the terminating null character. snprintf handles that by itself. So we pass the full size, sizeof g_results[i].
But all other lines are empty.
That is because your declaration of g_results was wrong. It declared 1,000 pointers, and you stored an address only in g_results[0][0], so all the other pointers were uninitialized.
This is all odd, you seem to just want:
// array of 100 arrays of 10 chars
char g_results[100][10];
for (int i = 0; i < 100, i++) {
// why snprintf+strcpy? Just write where you want to write.
snprintf(g_results[i], 10, "%.2f", results[i]);
// ^^^^^^^^ has to be float or double
// ^^ why 9? The buffer has 10 chars.
}
Only allocating space for the 1st element?
Yes, you are, you only assigned first element g_results[0][0] to malloc ( 100 * 10 ).
wrong usage of the pointers. Is there a way I can declare that array as a non-pointer, but still on the heap?
No. To allocate something on the heap you have to call malloc.
But there is no reason to use the heap, especially that you are on a microcontroller and especially that you know how many elements you are going to allocate. Heap is for unknowns, if you know that you want exactly 100 x 10 x chars, just take them.
Overall, consider reading some C books.
I do not know what that should mean.
You cannot assign to an array as a whole. You can assign to array elements, one by one.
#include<stdio.h>
int main ()
{char c[5];
scanf ("%s",&c);
printf("%s",c);}
So I have declared the array size to be 5.
But lets say when I type Elephant which is an 8 lettered word it still gets printed.Can someone explain why and also suggest what I should do so that the computer takes/considers my input only upto 5 characters.
This is non-deterministic behavior. The array is 5 characters in memory, but scanf is not safe. It is putting all 8 characters into sequential memory starting at c[0] although 3 of the characters are technically not part of the array c. The last three characters may end up getting changed by some other application or function because they are not owned by the array c.
If you use the proper scan_s function it will throw an error when you try to do this. You should always use the "safe" functions for this.
Any array like this is actually a pointer to the first element of the array and the [5] indicates a 5 memory location offset from the first memory location defined by "c". You can freely set the number inside [] to any offset although it may go outside the bounds of what you allocated to c.
In C, arrays have no bound-check. So basically, if you declare a 5-element array, you could store 100 elements in it and, if you are lucky (here, by lucky I mean to not overwrite some other, important things, that affect the program execution), it will work. But it is dangerous and wrong. It's your responsibility to make sure this will not happen.
the variable c is allocated into the stack, when allocating space into the stack, the compiler may allocate more than what you're function really need so, that why when you write 8 character into the stack of the function main, you don't receive a segmentation fault.
you should change you're code and use :
fgets(c, sizeof c, stdin);
this is my problem... I created an array of strings like this..
char *name[12];
Then the user types 12 different names so I can save them in that array. But it is known that if you don't initialize a variable it has 'garbage' in it. So I started saving the names correctly until the 5th name, then it crashes, I don't know why. So I tried to initialize every element but then it doesn't allow me to change the content.
This is how I write into every element of the array:
printf("Type your name: ");
fflush(stdin);
gets( name[0] ); //I use a for to move into every element
And I want to know if there's any way to initialize the array, and to change it's content after that. I've tried with strcpy(); but I had the same error. Or how to delete that 'garbage' to stop it from causing me errors.
Thanks, and sorry if I had any misspelling. English is not my native language.
You've allocated space for 12 pointers; you've never allocated the space for the 12 strings, let alone assigned the pointers to that space to the pointers in the array.
The problem is that you have your array of char pointers, but you haven't initialised them or allocated space for them in any way. So you don't know what will happen when you use the address it points to.
You would have to loop through the array and initialise the elements before you can use them.
name[0] = malloc (SIZE);
You can try reading user input to a buffer to get the length of the data entered, then mallocating just the correct amount of space, or having a pre-defined chunk of memory to allocate before using it.
How to allocate dynamic memory to an array where size or number of element is unknown
int *p = (int*)malloc(i*sizeof(int)); here i also dynamic mean i may be 1 or 1000 we don't know so how to allocate size
thanks
Start by allocating space for, say, 10 elements. If it grows past 10, then use realloc to grow the allocation to 20. If grows past 20, grow it to 40, and so on. Keep an 'alloc_size' variable and a 'count' variable. Before you add a new element, check if count == alloc_size, and if so, realloc.
you set a single variable of array type.
say ch,
get it from user,
use a pointer to implement array,
if ch!='\n'
realloc pointer
repeat getting input;
thats it.
I declared an array and take input from user. Now i want to check duplicate entries, they have to be deleted and memory should be freed. Is it possible to free memory.
freeing the unused memory and reducing the array size?
I entered [10,21,3,4,4,2,6,7,21,4,10].it should get truncated as [10,21,3,4,2,6,7] and array length should now be 7,and i don't want to use sorting.
In C, you cannot change the size of an array. If you use dynamically allocated memory (with malloc()), you can use realloc() to resize the memory region, or allocate a new region, copy the data into it and free the old one.
A solution that is often acceptable is to simply leave part of the array unused. This is done by recording how many entries are used in a separate integer variable.
Simple implementation:
When you do find a duplicate entry, shuffle the array left to fill the gap (covering the duplicate).
Use realloc to reduce your allocation.
Note that you simply can't delete an arbitrary memory location. If runtime for filling gaps is a problem, consider an alternate structure such as a linked list, which would allow removal from the middle.
Removing duplicate entries is another problem. The general case involves sorting. You may have a special case which allows for better behavior.
I declared an array of length 100 and took input from user
so you mean like this:
int input[100];
/* - ask 100 input from user */
Is it possible to free memory
the answer is no because you statically allocate 100 integers.
If you want to be able to reduce memory then you should do something like this:
int *tempBuffer=malloc(100*sizeof(int)); /* dynamic allocation */
for(i=0;i<100;++i) scanf("%d",&tempBuffer[i]);/* - ask 100 input from user */
int uniqueN=10 /* - assume the first 10 entries are the unique entries */
int *realBuffer=malloc(uniqueN*sizeof(int)); /* - allocate new buffer just enough for the unique entries */
for(i=0;i<uniqueN;++i) realBuffer[i]=tempBuffer[i]; /* - copy the unique entries from input to the final buffer */
free(tempBuffer); /* - tempBuffer is now unused, free it */
/* here we have realBuffer with just enough size, no unused memory */
Another solution is to realloc tempBuffer after arranging the first uniqueN entries to be the unique entries:
realloc(tempBuffer,uniqueN);
don't forget to check if malloc or realloc returns NULL
Arrays are not dynamic in C. That said, you can access entries beyond the last one (given that an array variable is essentially a pointer). However, this is not safe.
Also, you cannot delete "array entries". You can move the rest of the elements to occupy the respectively previous positions. However, you cannot actually delete the area occupied by the element since an array is a contiguous piece of memory.