fread weird behavior in c - c

I wrote a code just to understand how fread works and I don't understand how this is possible. Here my code :
#include <stdio.h>
#include <stdlib.h>
void main(){
char spool[5] = "hello";
fread(spool, sizeof(char), 6, stdin); //stdin == "bonjour"
printf("\n%s\n", spool);
}
So first, I thought spool's value would be replaced by "bonjo" but I got "bonjou". I don't understand why I get a 6 characters string instead of a 5 characters string.

char spool[5] = "hello";
This is wrong, because strings in C are null terminated. You don't allocate space for the null termination. A decent compiler should give you a warning about this. (Apparently gcc does not even with -Wall -Wextra, so that kind of sucks).
Reading "bounjour" into that array is also wrong, because C arrays have no boundary checks, nor do any of the library functions. So if you try to store more data in the array than you have room, you will write outside the boundaries of the array and the program will (hopefully) crash. You invoke undefined behavior, so anything might happen.
Solve this by declaring a large enough array, and study null termination of strings.

You need to increase the size of the spool buffer, (it cannot store more than 5 chars, that leads to Undefined beahvior):
#include <stdio.h>
#include <stdlib.h>
int main(){
char spool[15] = "hello";
fread(spool, sizeof(char), 6, stdin); //stdin == "bonjour"
printf("\n%s\n", spool);
}
Output:
bonjou

What you have is undefined behavior. You are trying to read 6 characters into a array which can hold 5 characters.Please note that the array should be large enough to hold a nul terminator.
Increase the size of your array spool to hold required characters.

Related

What if you dont allocate room for \0 using malloc?

From what I heard, I should allocate the memory like this in line 14:
array[i]=malloc(sizeof(char)*(strlen(buffer)+1)); I haven't added the 1 and still the code works perfect. I cant make it crash of return anything than 0. So, is the +1 needed or not? And if it is, what are the consequences going to be since my program runs smoothly?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 5
#define SIZE 512
int main(){
char *array[N];
char buffer[SIZE];
int i,j;
for(i=0;i<N;i++){
printf("Give word no.%d",i+1);
gets(buffer);
array[i]=malloc(sizeof(char)*strlen(buffer));
printf("%d",strlen(buffer));
if(!array[i]){
printf("Program will now exit.");
exit(0);
};
strcpy(array[i],buffer);
}
Tried it with both +1 and without. Same results although I've seen in tutorials that it is needed.
The +1 is needed to allocate room for the null terminator. If you don't, then you might write to the allocated array out of bounds, which is undefined behavior. What is undefined behavior and how does it work? Meaning it might seem to work just fine, to break mysteriously later on.
sizeof(char) is by definition always 1 though, so that part is not needed.
Recommendation: Use array[i] = malloc(strlen(buffer) + 1);
As a side note, whoever (book/teacher) told you to use gets should be retired and not be used as a source of learning C programming. Why is the gets function so dangerous that it should not be used?

Explanation on how does the memcpy function behaves? [duplicate]

This question already has answers here:
No out of bounds error
(7 answers)
Closed 5 years ago.
#include <stdio.h>
#include <string.h>
char lists[10][25];
char name[10];
void main()
{
scanf("%s" , lists[0]);
memcpy(name , lists[0], 25);
printf("%s\n" , name);
}
In the above code I am predefining the size of character array "name" as 10.
Now when I gave the input as :
Input - abcdefghijklmnopqrstuvwxy
The output I got was the same string : abcdefghijklmnopqrstuvwxy
Should'nt I get the output as : abcdefghij ???
how this is becoming possible even though the size of array is limited to 10?
Because it doesn't know the size of the allocated memory it's writing into, and you got away with where the extra data got written. You might not on another platform, or using a different compiler, or different optimisation settings.
When passing the size parameter to memcpy (), it's a good idea to take the size of the destination memory into account.
When using char arrays, if you want to be safer about not overrunning memory, you can use strncpy (). It'll take care of inserting the trailing NULL in the right place.
To start with, arrays are pointers. In C there are no length checks like on Java for example.
When you write char a[2]; the OS gives you space on the memory for 2 chars.
For example, let the memory be
|1|2|3|4|5|6|7|8|9|10|11|12|
a
a is a pointer to the address 1. The a[0] = 0; is equal with *(a+0) = 0, meaning write 0 to the address a + offset 0.
So if you try to write to an address that you have not allocated, unexpected things can happen.
For example, lets say we have char a[2];char b[2]; and the memory map is
|1|2|3|4|5|6|7|8|9|10|11|12|
a b
Then the a[2] = 0 is equal to b[0] = 0. But if this address is an address of an other program, then a segmentation error will be raised.
Try the program (it may work with no optimizations of the compiler):
#include <stdio.h>
#include <string.h>
char a[4];
char b[4];
void main()
{
scanf("%s" , a); // input "12345678"
printf("%s\n" , b); // print "5678"
}
memcpy just copies from an address to the other the size of data you said.
In your example, you were luky because all the addresses you accessed where assigned to your program (inside your's memory page).
In C/C++ you are responsible to handle the memory correctly. Also, keep in mind that strings end at the char \0 so inside an array char str[10]; we usually have tops 9 chars and the \0.

strcpy issue with char arrays in structs in C

So I'm working on a program to take in assembly code in a text file and produce the corresponding machine code. However, I'm running into an issue when I'm trying trying to assign values to the members of the AssemblyLine struct. What happens is that when ".fill" is the opcode, arg0 is concatenated to it, and there are also issues with arg0 if I assign value to arg0 first. It is important to note that this only happens when the opcode is ".fill". For example, if the opcode is "add" the values are what I intended for them to be.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct AssemblyLine {
char opcode[5];
char arg0[7];
char arg1[7];
char arg2[7];
_Bool initialized;
};
struct Label {
char name[7];
int address;
_Bool initialized;
};
main()
{
struct AssemblyLine line;
strcpy(line.opcode, ".fill");
strcpy(line.arg0, "5");
printf("%s\n", line.opcode);
return 0;
}
The output for this program is:
.fill5
My intention is that the output would just be:
.fill
I'm really confused about what would be causing this. Sorry if the answer is really obvious, this is my first time working in C, though I have programmed in C++ before. I was at first thinking that there was no null terminating character, but the string is read fine until after I use the second strcpy. Is fill used as a key word for strcpy or something? I thought maybe it had to do with the '.' but that didn't affect anything when the opcode was ".lw".
Sorry that this post is so long! Thanks for any help!
Your array isn't big enough. ".fill" is six characters include the terminating null, but you only allocate memory for five with char opcode[5]. You need to make your array bigger.
The string ".fill" is 5 characters + 1 zero character long. That makes 6 characters.
But the array 'opcode' is only 5 characters long, so the trailing zero is written to 'arg0'.
After that, your copy "5" (2 characters with zero) to 'arg0'.
Because 'printf' prints until the trailing zero occurs, it reads out of the bounds of opcode.

gets and puts to get and print a string

i'm trying to get and print a string with gets and puts but i get a segmentation fault error when i use them togheter.
this is the code i'm trying to get this working. [i type the string "prova" to test it]
int main()
{
char *s;
gets(s);
puts(s);
return 0;
}
if i change "gets" with "scanf" i get the same error.
if i change "puts" with "printf("%s", s)" i get the output.
if i declare char *s = "prova" and then puts(s) i get the output.
i also tried to change char *s; with char s[] but i get the same error.
where i'm i wrong on this? ty very much
i know gets is bad, is just bc i'm writing exercise from "C how to program, fifth edition" by Deitel and Deitel
You have multiple problems with that piece of code. To start with gets have been deprecated since the C99 standard, and in the C11 standard it has been removed. The reason is that it's not very safe, and has no bounds-checking and so can write beyond the bounds of the memory you pass to it leading to buffer overflows.
Secondly, you use the uninitialized local variable s. The value of an uninitialized variable is indeterminate, and will be seemingly random. Using an uninitialized local variable leads to undefined behavior, which often leads to crashes.
Another problem is if you initialize s to point to a literal strings. Literals strings are constant (read-only) arrays of characters, and attempting to write to it will again lead to undefined behavior.
You need to allocate some room for the string:
char s[256];
gets(s);
puts(s);
But gets is bad. (It doesn't know how big your buffer is, so what happens if more than 255 characters are read?)
The most important mistake you have is that you are declaring a char pointer, but you are not reserving the space in memory where the characters will be stored, so you got a pointer that point to some random memory adress that you should'nt use. the "right" thing to do will be:
#include <stdio.h>
#include <stdlib.h>
#define LENGHT 20
int main()
{
char *s;
s=malloc(sizeof(char)*LENGHT); //here you make the pointer point to a memory adress that you can use
gets(s);
puts(s);
free (s);
return 0;
}
But also is strongly recommend to avoid using gets because that function doesn't check for the length of the input, so use fgets instead that allow you to do that, you will only need to set the data stream to stdin.
The code will be:
#include <stdio.h>
#include <stdlib.h>
#define LENGHT 20
int main()
{
char *s;
s=malloc(sizeof(char)*LENGHT);
fgets(s,20,stdin);
puts(s);
free(s);
return 0;
}

Creating one array of strings in C fails, why?

I tried to create one array of strings in C. Here is the code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main()
{
char *foo[100];
strcpy(foo[0], "Testing this");
printf("%s ", foo[0]);
return 1;
}
But when I compile it, it simply breaks. No error, no nothing, it simply doesn't work and breaks. Any suggestion? When I tri char *foo[10] it works, but I can't work with just 10 strings
You allocated an array of pointers but did not allocate any memory for them to point to. You need to call malloc to allocate memory from the heap.
char *foo[100];
foo[0] = malloc(13);
strcpy(foo[0], "Testing this");
Naturally you would need to free the memory at some later date when you were finished with it.
Your code invokes what is known as undefined behavior. Basically anything can happen, including the code working as you intended. If the version with char *foo[10] works as you intended that's simply down to luck.
As an aside, your main() definition is wrong. It should be int main(void).
You're assigning an unallocated pointer. char *foo[100] is an array of 100 unallocated pointers, and they point to unknown locations in memory, ones which you can probably not access.
You are creating an 100 pointers to point no where. As explained by David, you need to dynamically allocate the memory. However, you can also have the compiler do this for you if you know the size of the strings (or max):
// Create an array of 10 strings of size 100 and initialize them automatically
char foo[10][100] = {0};
// Now you can use it them and not worry about memory leaks
strcpy(foo[0], "text");
// Or use the safer version
strcpy_s(foo[0], 100, "text");
Expanding upon other people's answers:
char *foo;
is a pointer to a character. It may be assigned the address of a single character or assigned the address of the first of a sequence of characters terminated by '\0'. It may also be assigned an address via malloc().
char foo[100];
is space for 100 characters or space for a string of up to 99 characters and a terminating '\0' character.
char *foo[100];
is 100 character pointers, i.e., 100 char *foo; types.
#include <stdlib.h>
#include <stdio.h>
int main(void){
char *foo[100];
foo[0] = malloc(13*(sizeof(char)));
strcpy(foo[0], "Testing this");
printf("%s ", foo[0]);
return 0;
}
This is the corrected version of your code.
MISTAKE: not allocating enough memory for the string.
CORRECTION: using malloc to allocate 13 blocks of memory for the string.

Resources