may you please tell me why by running this two codes I have different output?
void UART_OutString(unsigned char buffer[]){
int i;
while(buffer[i]){
UART_OutChar(buffer[i]);
i++;
}
}
and
void UART_OutString(unsigned char buffer[]){
int i = 0;
while(buffer[i]){
UART_OutChar(buffer[i++]);
}
}
regards, Genadi
You didn't initialize the i variable in the first case, so it's an uninteresting typo bug that your compiler ought to warn you about...
That being said, we can apply the KISS principle and rewrite the whole code in the most readable way possible, a for loop, which by its nature makes it very hard to forget to initialize the loop iterator:
void UART_OutString(const char* buf[]){
for(int i=0; buf[i]!='\0'; i++){
UART_OutChar(buffer[i]);
}
}
As it turns out, the most readable way is very often the fastest way possible too.
(However, int might be inefficient on certain low-end systems, so if you are fine with only using strings with length 255 or less, uint8_t i would be a better choice. Embedded systems should never use int and always the stdint.h types.)
For what it's worth, I'd implement this as
void UART_OutChar(unsigned char c);
void UART_OutString(unsigned char buffer[]){
for(unsigned char *p = buffer; *p; p++) {
UART_OutChar(*p);
}
}
to avoid the separate counter variable at all.
It is always a good idea to initialize local variables, especially in C where you should assume that nothing is done for you (because that's usually the case). There is a reason why regulated languages would not allow you to do this.
I believe reading the unassigned variable will result in unspecified behaviour (effectively C doesn't know there isn't meant to be anything there and will just grab what ever), this means it is completely un-predictable.
This could also cause all kinds of problems as you then index an array with it and C will not stop you from indexing an array out of bounds so if the random i value C happens to grab is larger than the size of the array then you will experience undefined behaviour in what buffer[i] returns. This one could be particularly nasty as it could cause any kind of memory read / segmentation fault are crash your program depending on quite what it decides to read.
Therefor unassigned i = random behaviour, and you then get more random behaviour from using that i value to index your array.
I believe this is about all the reasons that this is a bad idea. In C it is particular important to pay attention to things like this as it will often allow you to compile and run your code.
Both initialising i, and using the solution in #AKX's answer are good solutions although i thaught this would more answer your question of why they return differently. To which really the answer is the first approach returns completely randomly
Related
Recently I needed to compare two uint arrays (one volatile and other nonvolatile) and results were confusing, there got to be something I misunderstood about volatile arrays.
I need to read an array from an input device and write it to a local variable before comparing this array to a global volatile array. And if there is any difference i need to copy new one onto global one and publish new array to other platforms. Code is something as blow:
#define ARRAYLENGTH 30
volatile uint8 myArray[ARRAYLENGTH];
void myFunc(void){
uint8 shadow_array[ARRAYLENGTH],change=0;
readInput(shadow_array);
for(int i=0;i<ARRAYLENGTH;i++){
if(myArray[i] != shadow_array[i]){
change = 1;
myArray[i] = shadow_array[i];
}
}
if(change){
char arrayStr[ARRAYLENGTH*4];
array2String(arrayStr,myArray);
publish(arrayStr);
}
}
However, this didn't work and everytime myFunc runs, it comes out that a new message is published, mostly identical to the earlier message.
So I inserted a log line into code:
for(int i=0;i<ARRAYLENGTH;i++){
if(myArray[i] != shadow_array[i]){
change = 1;
log("old:%d,new:%d\r\n",myArray[i],shadow_array[i]);
myArray[i] = shadow_array[i];
}
}
Logs I got was as below:
old:0,new:0
old:8,new:8
old:87,new:87
...
Since solving bug was time critical I solved the issue as below:
char arrayStr[ARRAYLENGTH*4];
char arrayStr1[ARRAYLENGTH*4];
array2String(arrayStr,myArray);
array2String(arrayStr1,shadow_array);
if(strCompare(arrayStr,arrayStr1)){
publish(arrayStr1);
}
}
But, this approach is far from being efficient. If anyone have a reasonable explanation, i would like to hear.
Thank you.
[updated from comments:]
For the volatile part, global array has to be volatile, since other threads are accessing it.
If the global array is volatile, your tracing code could be inaccurate:
for(int i=0;i<ARRAYLENGTH;i++){
if(myArray[i] != shadow_array[i]){
change = 1;
log("old:%d,new:%d\r\n",myArray[i],shadow_array[i]);
myArray[i] = shadow_array[i];
}
}
The trouble is that the comparison line reads myArray[i] once, but the logging message reads it again, and since it is volatile, there's no guarantee that the two reads will give the same value. An accurate logging technique would be:
for (int i = 0; i < ARRAYLENGTH; i++)
{
uintu_t value;
if ((value = myArray[i]) != shadow_array[i])
{
change = 1;
log("old:%d,new:%d\r\n", value, shadow_array[i]);
myArray[i] = shadow_array[i];
}
}
This copies the value used in the comparison and reports that. My gut feel is it is not going to show a difference, but in theory it could.
global array has to be volatile, since other threads are accessing it
As you "nicely" observe declaring an array volatile is not the way to protect it against concurrent read/write access by different threads.
Use a mutex for this. For example by wrapping access to the "global array" into a function which locks and unlocks this mutex. Then only use this function to access the "global array".
References:
Why is volatile not considered useful in multithreaded C or C++ programming?
https://www.kernel.org/doc/Documentation/volatile-considered-harmful.txt
Also for printf()ing unsigned integers use the conversion specifier u not d.
A variable (or Array) should be declared volatile when it may Change outside the current program execution flow. This may happen by concurrent threads or an ISR.
If there is, however, only one who actually writes to it and all others are jsut Readers, then the actual writing code may treat it as being not volatile (even though there is no way to tell teh Compiler to do so).
So if the comparison function is the only Point in the Project where teh gloal Array is actually changed (updated) then there is no Problem with multiple reads. The code can be designed with the (external) knowledge that there will be no Change by an external source, despite of the volatile declaration.
The 'readers', however, do know that the variable (or the array content) may change and won't buffer it reads (e.g by storing the read vlaue in a register for further use), but still the array content may change while they are reading it and the whole information might be inconsistent.
So the suggested use of a mutex is a good idea.
It does not, however, help with the original Problem that the comparison Loop fails, even though nobody is messing with the array from outside.
Also, I wonder why myArray is declared volatile if it is only locally used and the publishing is done by sending out a pointer to ArrayStr (which is a pointer to a non-volatile char (array).
There is no reason why myArray should be volatile. Actually, there is no reason for its existence at all:
Just read in the data, create a temporary tring, and if it differes form the original one, replace the old string and publish it. Well, it's maybe less efficient to always build the string, but it makes the code much shorter and apparently works.
static char arrayStr[ARRAYLENGTH*4]={};
char tempStr[ARRAYLENGTH*4];
array2String(tempStr,shadow_array);
if(strCompare(arrayStr,tempStr)){
strCopy(arrayStr, tempStr);
publish(arrayStr);
}
}
I'm learning C and trying to build an dynamic array. I found a great tutorial on this but I don't get it all the way. The code I have now is
typedef struct{
int size;
int capacity;
char *data;
}Brry;
void brry_init(Brry *brry){
brry->size = 0;
brry->capacity = 2;
brry->data = (char *)calloc(brry->capacity, sizeof(char));
}
void brry_insert(Brry *brry, char value){
brry->data[brry->size++] = value; //so do check here if I have enough memory, but checking something out
}
int main(void){
Brry brry;
brry_init(&brry);
for (int i = 0; i < 3; i++) {
brry_insert(&brry, 'a');
}
printf("%c\n", brry.data[2]);
return 0;
}
In my main function I add 3 element to the array, but it only allocated for 2. But when I print it it works just fine? I expected some strange value to be printed. Why is this or am I doing something wrong?
You are writing into a buffer you didn't allocate enough memory for. That it works is not guaranteed.
What you're trying now is to read from some junk value in memory, who knows, which sometimes leads to a segmentation fault and other times you are lucky and get some junk value, and it doesn't segfault.
Writing into junk memory will invoke undefined behavior, so better watch it.
If you do get errors it will almost always be a segfault, short for segmentation fault.
Read up on it here.
The technical for what you're doing by reading past the bounds of the array is called derefencing a pointer. You might also want to read more about that here.
Yes, you are indeed writing to the third element of a two element array. This means your program will exhibit undefined behavior and you have no guarantee of what is going to happen. In your case you got lucky and the program "worked", but you might not always be so lucky.
Trying to read/write past the end of the array results in undefined behaviour. Exactly what happens depends on several factors which you cannot predict or control. Sometimes, it will seem to read and/or write successfully without complaining. Other times, it may fail horribly and effectively crash your program.
The critical thing is that you should never try to use or rely on undefined behaviour. It's unfortunately a common rookie mistake to think that it will always work because one test happened to succeed. That's definitely not the case, and is a recipe for disaster sooner or later.
I am working my way thru Cyclone: A Safe Dialect of C for a PL class. The paper's authors explain that they've added a special 'fat' pointer that stores bounds information to prevent buffer overflows. But they don't specify if the check on this pointer is static or dynamic. The example they give seems to imply that the programmer must remember to check the size of the array in order to check that they don't exceed the buffer. This seems to open up the possibility of programming errors, just like in C. I thought the whole idea of Cyclone was to make such errors impossible. Does the language have a check? Does it just make it harder to make programming mistakes?
int strlen(const char ?s) {
int i, n;
if (!s) return 0;
n = s.size; //what if the programmer forgets to do this.. or accidentally adds an n++;
for (i = 0; i < n; i++,s++)
if (!*s) return i;
return n;
}
"Fat" pointers support pointer arithmetic with run-time bounds
checking.
Obtained from Wikipedia by googling for “fat pointers”.
i was just trying to check the default value of int and char when not initialised in c.
my problem is that i get two different outputs when i use clrscr() to clear the screen between 2 runs.could someone explain this behavior to me?
here is the code
void main()
{
int i;
char c;
printf("%d %c",i,c);
}
output: 0
void main()
{
int i;
char c;
clrscr();
printf("%d %c",i,c);
}
output:-29542 //some garbage value which is what i was expecting in both cases
You shouldn't be expecting anything in particular. The values are uninitialized, i.e.: can be anything.
Why the garbage value in the first case differs from the garbage value in the second case? Who knows? Different memory map, different execution paths - different garbage.
I think it always give some garbage value ..you can't determine the behavior... :-/
In case of your code, you will get garbage values, but if the integer varibale was declared globally then its default value will be 0 for sure in C.
I mentioned this because question's title was-"Default values of int when not initialized in c".
Actually zeros were garbage as well. After you add clrscr(); you changed stack so you did to garbage.
In managed code, there are default values, usually 0 or equivalent.
In the unmanaged world, there is no default value. When the memory is allocated, the system just tells you "You can write here is you want, but I don't know what mess the previous program let behind".
This behaviour is seen for some people as bad since their program can be unpredictable for some obscure reasons, but it is also a way to be able to optimize as much as we can memory management, think of large buffer allocation which when allocated would be filled with 0s, and then filled with actual data. You get twice the performance in unmanaged code!
I wrote this code today, just out of experimentation, and I'm trying to figure out the output.
/*
* This code in C attempts to exploit insufficient bounds checking
* to legitimate advantage.
*
* A dynamic structure with the accessibility of an array.
* Handy for small-time code, but largely unreliable.
*/
int array[1] = {0};
int index = 0;
put(), get();
main ( )
{
put(1); put(10), put(100);
printf("%6d %5d %5d\n", get(0), get(1), get(2));
}
put ( x )
int x;
{
array[index++] = x;
}
get ( index )
int index;
{
return array[index];
}
The output:
1 3 100
There is a problem there, in that you declare 'array' as an array of length 1 but you write 3 values to it. It should be at least 'array[3]'. Without that, you are writing to unallocated memory, so anything could happen.
The reason it outputs '3' there without the fix is that it is outputting the value of the global 'index' variable, which is the next int in memory (in your case - as I said anything could happen). Even though you do overwrite this with your put(10) call, the index value is used in as the index in the assignment and then post-incremented, which will set it back to 2 - it then gets set to 3 at the end of the put(100) call and subsequently output via printf.
It's undefined behavior, so the only real explanation is "It does some things on one machine and other things on other machines".
Also, what's with the K&R function syntax?
EDIT: The printf guess was wrong. As far as the syntax, read K&R 2nd Edition (the cover has a red ANSI stamp), which uses modern function syntax (among other useful updates).
To expand on what has been said, accessing out-of-bounds array members results in undefined behavior. Undefined behavior means that literally anything could happen. There is no way to exploit undefined behavior unless you're deep into esoteric platform-specific hacks. Don't do it.
If you do want a "dynamic array", you'll have to take care of it yourself. If your requirements are simple, you can just malloc and realloc a buffer. If your needs are more complicated, you might want to define a struct that keeps a separate buffer, a size, and a count, and write functions that operate on that struct. If you're just learning, try it both ways.
Finally, your function declaration syntax is valid, but archaic. That form is rarely seen, and virtually unheard of in new code. Declare put as:
int put(int x) {…}
And always declare main as:
int main(int argc, char **argv) {…}
The names of argc and argv aren't important, but the types are. If you forget those parameters, demons could fly out of your nose.