What is going on in this simple C code? - c

I am in the process of teaching myself C. I have the following code that prints a string char by char forwards and backwards:
#include<stdio.h>
#include<string.h>
main(){
char *str;
fgets(str, 100, stdin);
//printf("%i", strlen(str));
int i;
for(i = 0; i < strlen(str) - 1; i++){
printf("%c", str[i]);
}
for(i = strlen(str); i > -1; i--){
printf("%c", str[i]);
}
}
When run, it gives me the following output (assuming I typed "hello"):
cello
ollec
In addition, if I uncomment the 7th line of code, I get the following output (assuming I typed "hello"):
6 ♠
For the life of me, I cannot figure out what I am doing that is causing the first character in the output to change. In the second example, I know that the string length would be 6 because 'h' + 'e' + 'l' + 'l' + 'o' + '\0' = 6. That is fine, but where is the spade symbol coming from? Why is it only printing one of them?
It is pretty obvious to me that I have some kind of fundamental misunderstanding of what is happening under the hood here and I cant find any examples of this elsewhere. Can anyone explain what is going wrong here?

You never allocate memory for the string. Instead of
char *str;
use
char str[100];
so that you have enough space for the up to 100 characters you read in there with the fgets call.

In this code:
char *str;
fgets(str, 100, stdin);
str points to an effectively random location. Then you tell fgets to read characters and put them where str is pointing. This causes undefined behaviour; the symptoms you are seeing probably occur because str happened to point to some memory where the first character of that memory that was being used for other purposes, but the other characters weren't being used.
Instead you need to allocate memory:
char str[100]; // allocate 100 bytes
fgets(str, 100, stdin);
Pointers only point at memory which already is allocated somewhere; they do not "own" or "contain" any memory.

You should preallocate space for your string, otherwise you are writing to who knows where, which is bad.
char str[100]; //I must be big enough to hold anything fgets might pass me
You should also be sure to only access parts of the string which contain characters:
for(i = strlen(str)-1; i > -1; i--){
printf("%c", str[i]);
}
Note that the character at strlen(str) is \0, the string-terminating null character. So you can access this space, but trying to print it or otherwise treating it like a standard letter is going to lead to issues at some point.

Your str is a pointer to char, but you don't have any actual character buffer for it to point to. You need a character array instead:
char str[100];
Only then can fgets have somewhere to store the data it reads.
Then on your reverse-printing loop, your indices are wrong:
for(i = strlen(str); i > -1; i--){
With the above, you try to print str[i] for i = strlen(str), but that's one past the end of the valid string data. Change to:
for(i = strlen(str) - 1; i > -1; i--){

The issue is that you are not allocating your
char *str
what you need to do is either
1)
char *str = malloc(sizeof(char) * 100);
and then when you are no longer using it:
free(str)
2)
char str[100];

Related

Add one character from a string to the end of another string (strcat)

for (unsigned int i = 0; i < strlen(s); i++) {
if (s[i] != ' ')
strcat(p, s[i]);
I want to add the current character of the s string at the end of the p string provided it is not a space. How do I do that using strcat? The code above gives the following error "invalid conversion from 'char' to 'const char*'".
I want to use strcat because this way I don't have to store an index for p string in order to know where to place the current character. I hope this makes sense.
Also, I need to do this using array of chars, not c-strings or whatever those are called.
A more sensible algorithm would avoid using strcat() or strncat() altogether:
int j = strlen(p);
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] != ' ')
p[j++] = s[i];
}
p[j] = '\0';
This avoids quadratic behaviour which using strlen() and strcat() (or strncat()) necessarily involves. It does mean you need to keep a track of where to place characters in p, but the work involved in doing that is trivial. Generally speaking, the quadratic behaviour won't be a problem on strings of 10 characters or so, but if the strings reach 1000 bytes or more, then quadratic behaviour becomes a problem (it takes 1,000,000 operations instead of 1,000 operations — that can become noticeable).
First, you need addresses (the array itself is an address to the first element) to pass to the strcat, not a char. That is why you need to use the & operator before s[i].
You have a working example here
#include <stdio.h>
#include <string.h>
int main()
{
char s[50]= "Hello World";
char p[50]= "Hello World";
for(unsigned int i=0;i<strlen(s);i++){
if(s[i]!=' ')
strncat(p,&s[i],1);
}
puts(p);
return 0;
}

Print one character from string

I'm facing an issue connected with printing one char from string in c.
The function takes from users two variables - number (number which should print character from string) and string. When I put as a string "Martin" and number is 5 then the output is "i". But when the number is larger than the string length something goes wrong and I actually don't know what's wrong.
PS. If the number is longer than string size it should print "Nothing".
void printLetter() {
char * string = (char*)malloc(sizeof(char));
int n;
printf("Number:\n");
scanf("%i", &n);
printf("String:\n");
scanf("%s", string);
if(n > strlen(string)) {
printf("nothing");
} else {
printf("%c\n", string[n+1]);
}
free(string);
}
There is no need for dynamic allocation here, since you do not know the length of the string in advance, so just do:
void printLetter() {
char string[100]; // example size 100
...
scanf("%99s", string); // read no more than your array can hold
}
A fun exercise would be to count the length of the string, allocate dynamically exactly as mush space as you need (+1 for the null terminator), copy string to that dynamically allocated space, use it as you wish, and then free it.
Moreover this:
printf("%c\n", string[n+1]);
should be written as this:
printf("%c\n", string[n-1]);
since you do not want to go out bounds of your array (and cause Undefined Behavior), or print two characters next of the requested character, since when I ask for the 1st character, you should print string[0], when I ask for the 2nd, you should print string[1], and so on. So you see why we need to print string[n-1], when the user asks for the n-th letter.
By the way, it's common to use a variable named i, and not n as in your case, when dealing with an index. ;)
In your code, this:
char * string = malloc(sizeof(char));
allocates memory for just one character, which is no good, since even if the string had one letter only, where would you put the null terminator? You know that strings in C should (almost) always be NULL terminated.
In order to allocate dynamically memory for a string of size N, you should do:
char * string = malloc((N + 1) * sizeof(char));
where you allocate space for N characters, plus 1 for the NULL terminator.
Couple of problems...
sizeof(char) is generally 1 byte. Hence malloc() is allocating only one byte of memory to string. Perhaps a larger block of memory is required? "Martin", for example, will require at least 6 bytes, plus the string termination character (seven bytes total).
printf("%c\n", string[n+1]) is perhaps not quite right...
String: Martin\0
strlen= 6
Offset: 0123456
n = 5... [n+1] = 6
The character being output is the string terminator '\0' at index 6.
This might work better:
void printLetter() {
char * string = malloc(100 * sizeof(char));
int n;
printf("Number:\n");
scanf("%i", &n);
printf("String:\n");
scanf("%s", string);
if(n > strlen(string)) {
printf("nothing");
} else {
printf("%c\n", string[n-1]);
}
free(string);
}
You are facing buffer overflow.
Take a look to this question, so it will show you how to manage your memory properly in such situation: How to prevent scanf causing a buffer overflow in C?
Alternatively you can ask for number of letter and allocate only that much memory + 1. Then fgets(string, n,stdin); because you don't need rest of the string :-)

why is my printf doing this?

it seems like such a silly thing to ask but i seriously don't know why this is happening. Could be that it's almost 5am and i'm still doing this but..
It should print -CA but why when i compile it, it is printing
-
CA?
instead of -CA, there isn't a '\n' anywhere in sight.
Can you guys think of anything logical that would explain it?
int main(int argc, char* argv[]){
int check = 0;
char *thing = (char*)malloc(2 * sizeof(char));
strcpy(char, "CA");
some code..
do{
more code...
if(condition== 1) {
more code....
if(check == 0) {
printf("-");
check++;
}
if (some conditon != NULL){
printf("%s\n",thing);
}while(condition)
return 0;
}
You didn't allocate enough space for your string. Every string has a null terminator, so a 2-character string needs 3 bytes in the array. Your strcpy() is writing outside the bounds of the thing array when it copies the null byte, which results in undefined behavior.
Use
char *thing = malloc(3);
You can also use strdup(), which makes a copy of a string in dynamic memory, automatically allocating enough space based on the length of the original string.
char *thing = strdup("CA");
printf prints a null terminated string to the stdout. if the sting is not null terminated the printf will go on printing garbage to the stdout till a null terminator is met
so you should all one to your character array
char thing[3] = {'C','A',0};
now printf will print
-
CA

Need help finding bug, if string input is composed all of same character one output character is corrupt

reverser() reverses a cstring (not in place). 99% of the time it works but some input corrupts it for example it appears if aStr2[] is assigned a string made up of the same character it will have an error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverser(const char *str);
int main()
{
char aStr[] = "aaa";
char aStr2[] = "cccccc";
printf("%s %s", aStr, aStr2);
char* tmp = reverser(aStr2);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr2);
return 0;
}
char* reverser(const char *str)
{
char* revStr = (char*)malloc(strlen(str));
int i;
for(i = strlen(str)-1; i >= 0; i--)
{
revStr[strlen(str)-1-i] = str[i];
}
return revStr;
}
Gives
aaa cccccc
cccccc9 cccccc
Process returned 0 (0x0) execution time : 0.068 s
Press any key to continue
Notice the 9 that shouldn't be there.
Change this malloc to strlen(str) + 1 , plus 1 for '\0'
char* revStr = (char*)malloc(strlen(str) + 1);
and after the for loop
revStr[strlen(str)+1] = '\0';
Your problem is that you don't put the string terminator in your reversed string. All strings in C are actually one extra character that isn't reported by strlen, and that is the character '\0' (or plain and simple, a zero). This tells all C functions when the string ends.
Therefore you need to allocate space for this extra terminator character in your malloc call, and add it after the last character in the string.
There are also a couple of other problems with your code, the first is that you should not cast the return of malloc (or any other function returning void *). Another that you have a memory leak in that you do not free the memory you allocate. This last point doesn't matter in a small program like the one you have here, but will be an issue in larger and longer running programs.
You haven't null-terminated your reversed string. You need to set the final index of revStr[] to 0.

C reverse function wont work with 32 characters

To test my skills, I'm trying to write my own version of a few standard library functions. I wrote a replacement for strlen(), strlength():
int strlength(const char *c){
int len = 0;
while (*c != '\0') {
c++;
len++;
}
return len;
}
which doesn't include the null-terminator, and I am trying to write a function to reverse a string. This:
char *reverse(const char *s){
char *str = (char *)malloc(sizeof(char) * strlength(s));
int i = 0;
while (i < strlength(s)) {
str[i] = s[(strlength(s) - 1) - i];
i++;
}
str[strlength(s)] = '\0';
return str;
}
works for every string except for one with 32 characters (not including null-terminator) like foofoofoofoofoofoofoofoofoofoofo. It hangs in the reverse() functions while-loop. For all other amounts of characters, it works. Why is this happening?
Your buffer for str is off by 1. Your writes are overflowing into the rest of your heap.
As for why it works for values other than 32, my guess is that it has to do with the heap's memory alignment. The compiler is adding extra padding for smaller buffer sizes, but 32 bytes is nicely aligned (it's a power of 2, multiple of 8, etc.), so it doesn't add the extra padding and that's causing your bug to manifest. Try some other multiples of 8 and you'll probably get the same behavior.
char *reverse(const char *s){
here you allocate N characters (where N is the length of s without \0):
char *str = (char *)malloc(sizeof(char) * strlength(s));
then you iterate N times over all characters of s
int i = 0;
while (i < strlength(s)) {
str[i] = s[(strlength(s) - 1) - i];
i++;
}
and finally you add \0 at N+1 characters
str[strlength(s)] = '\0';
return str;
}
so you should do instead:
char *str = malloc(sizeof(*str) * strlength(s) + 1); // +1 for final `\0`
and funny thing is that I just tested your code, and it works fine for me (with one character off) and your 32 characters string. As #JoachimPileborg says, "That's the fun thing about undefined behavior"!
As suggested by others, the problem is certainly due to memory alignment, when you get your data aligned with your memory it overflows, whereas when it is not aligned it overwrites padding values.
You asked:
But this works for every other string length. Why won't it for 32?
Most likely because the runtime allocates memory in blocks of 32 bytes. So a 1-character buffer overrun when the buffer size is, say, 22 bytes, isn't a problem. But when you allocate 32 bytes and try to write to the 33rd byte, the problem shows up.
I suspect you'd see the same error with a string of 64 characters, 96, 128, etc . . .
Replace
malloc(sizeof(char) * strlength(s))
by
malloc(sizeof(char) * (1+strlength(s)));
The line:
str[strlength(s)] = '\0';
works often as the malloc library routine reserves word boundary aligned block and allocates only as much of it as requested in the call, viz. power of 2, but when the overflowing data overwrites beyond the allocated part, then examining the disassembly through debugger is the best hack to understand the build tool-chain specific to target's behavior. As the line is following the while loop rather than within it, so without disassembly how is the while loop mutating into infinite is unpredictable.
What everybody else said about buffer overflow and the vagaries of your runtime's memory allocation implementation/strategy. The size of a C-string is 1 more than its length, due to the NUL-termination octet.
Something like this ought to do you (a little cleaner and easier to read):
#define NUL ((char)0) ;
char *reverse( const char *s )
{
int len = strlen(s) ;
char *tgt = ((char*)malloc( 1+len )) + len ;
char *src = s ;
*(tgt--) = NUL ;
while ( *src )
{
*(tgt--) = *(src++) ;
}
return tgt;
}
Your strlen() implementation is more complicated than it needs to be, too. This is about all you need:
int string_length( const char *s )
{
char *p = s ;
while ( *p ) ++p ;
return p - s ;
}

Resources