Find String Length without recursion in C - c

#include<stdio.h>
#include<conio.h>
void main()
{
int str1[25];
int i=0;
printf("Enter a string\n");
gets(str1);
while(str1[i]!='\0')
{
i++;
}
printf("String Length %d",i);
getch();
return 0;
}
i'm always getting string length as 33. what is wrong with my code.

That is because, you have declared your array as type int
int str1[25];
^^^-----------Change it to `char`

You don't show an example of your input, but in general I would guess that you're suffering from buffer overflow due to the dangers of gets(). That function is deprecated, meaning it should never be used in newly-written code.
Use fgets() instead:
if(fgets(str1, sizeof str1, stdin) != NULL)
{
/* your code here */
}
Also, of course your entire loop is just strlen() but you knew that, right?
EDIT: Gaah, completely missed the mis-declaration, of course your string should be char str1[25]; and not int.

So, a lot of answers have already told you to use char str1[25]; instead of int str1[25] but nobody explained why. So here goes:
A char has length of one byte (by definition in C standard). But an int uses more bytes (how much depends on architecture and compiler; let's assume 4 here). So if you access index 2 of a char array, you get 1 byte at memory offset 2, but if you access index 2 of an int array, you get 4 bytes at memory offset 8.
When you call gets (which should be avoided since it's unbounded and thus might overflow your array), a string gets copied to the address of str1. That string really is an array of char. So imaging the string would be 123 plus terminating null character. The memory would look like:
Adress: 0 1 2 3
Content: 0x31 0x32 0x33 0x00
When you read str1[0] you get 4 bytes at once, so str1[0] does not return 0x31, you'll get either 0x00333231 (little-endian) or 0x31323300 (big endian).
Accessing str1[1] is already beyond the string.
Now, why do you get a string length of 33? That's actually random and you're "lucky" that the program didn't crash instead. From the start address of str1, you fetch int values until you finally get four 0 bytes in a row. In your memory, there's some random garbage and by pure luck you encounter four 0 bytes after having read 33*4=132 bytes.
So here you can already see that bounds checks are very important: your array is supposed to contain 25 characters. But gets may already write beyond that (solution: use fgets instead). Then you scan without bounds and may thus also access memory well beyond you array and may finally run into non-existing memory regions (which would crash your program). Solution for that: do bounds checks, for example:
// "sizeof(str1)" only works correctly on real arrays here,
// not on "char *" or something!
int l;
for (l = 0; l < sizeof(str1); ++l) {
if (str1[l] == '\0') {
// End of string
break;
}
}
if (l == sizeof(str1)) {
// Did not find a null byte in array!
} else {
// l contains valid string length.
}

I would suggest certain changes to your code.
1) conio.h
This is not a header that is in use. So avoid using it.
2) gets
gets is also not recommended by anyone. So avoid using it. Use fgets() instead
3) int str1[25]
If you want to store a string it should be
char str1[25]

The problem is in the string declaration int str1[25]. It must be char and not int
char str1[25]

void main() //"void" should be "int"
{
int str1[25]; //"int" should be "char"
int i=0;
printf("Enter a string\n");
gets(str1);
while(str1[i]!='\0')
{
i++;
}
printf("String Length %d",i);
getch();
return 0;
}

Related

string gets filled with garbage

i got a string and a scanf that reads from input until it finds a *, which is the character i picked for the end of the text. After the * all the remaining cells get filled with random characters.
I know that a string after the \0 character if not filled completly until the last cell will fill all the remaining empty ones with \0, why is this not the case and how can i make it so that after the last letter given in input all the remaining cells are the same value?
char string1 [100];
scanf("%[^*]s", string1);
for (int i = 0; i < 100; ++i) {
printf("\n %d=%d",i,string1[i]);
}
if i try to input something like hello*, here's the output:
0=104
1=101
2=108
3=108
4=111
5=0
6=0
7=0
8=92
9=0
10=68
You have an uninitialized array:
char string1 [100];
that has indeterminate values. You could initialize the array like
char string1 [100] = { 0 };
or
char string1 [100] = "";
In this call
scanf("%[^*]s", string1);
you need to remove the trailing character s, because %[] and %s are distinct format specifiers. There is no %[]s format specifier. It should look like this:
scanf("%[^*]", string1);
The array contains a string terminated by the zero character '\0'.
So to output the string you should write for example
for ( int i = 0; string1[i] != '\0'; ++i) {
printf( "%c", string1[i] ); // or putchar( string1[i] );
putchar( '\n' );
or like
for ( int i = 0; string1[i] != '\0'; ++i) {
printf("\n %d=%c",i,string1[i]);
putchar( '\n' );
or just
puts( string1 );
As for your statement
printf("\n %d=%d",i,string1[i]);
then it outputs each character (including non-initialized characters) as integers due to using the conversion specifier d instead of c. That is the function outputs internal ASCII representations of characters.
I know that a string after the \0 character if not filled completly
until the last cell will fill all the remaining empty ones with \0
No, that's not true.
It couldn't be true: there is no length to a string. No where neither the compiler nor any function can even know what is the size of the string. Only you do. So, no, string don't autofill with '\0'
Keep in minds that there aren't any string types in C. Just pointer to chars (sometimes those pointers are constant pointers to an array, but still, they are just pointers. We know where they start, but there is no way (other than deciding it and being consistent while coding) to know where they stop.
Sure, most of the time, there is an obvious answer, that make obvious for any reader of the code what is the size of the allocated memory.
For example, when you code
char string1[20];
sprintf(string1, "hello");
it is quite obvious for a reader of that code that the allocated memory is 20 bytes. So you may think that the compiler should know, when sprinting in it of sscaning to it, that it should fill the unused part of the 20 bytes with 0. But, first of all, the compiler is not there anymore when you will sscanf or sprintf. That occurs at runtime, and compiler is at compilation time. At run time, there is not trace of that 20.
Plus, it can be more complicated than that
void fillString(char *p){
sprintf(p, "hello");
}
int main(){
char string1[20];
string1[0]='O';
string1[1]='t';
fillString(&(string1[2]));
}
How in this case does sprintf is supposed to know that it must fill 18 bytes with the string then '\0'?
And that is for normal usage. I haven't started yet with convoluted but legal usages. Such as using char buffer[1000]; as an array of 50 length-20 strings (buffer, buffer+20, buffer+40, ...) or things like
union {
char str[40];
struct {
char substr1[20];
char substr2[20];
} s;
}
So, no, strings are not filled up with '\0'. That is not the case. It is not the habit in C to have implicit thing happening under the hood. And that could not be the case, even if we wanted to.
Your "star-terminated string" behaves exactly as a "null-terminated string" does. Sometimes the rest of the allocated memory is full of 0, sometimes it is not. The scanf won't touch anything else that what is strictly needed. The rest of the allocated memory remains untouched. If that memory happened to be full of '\0' before the call to scanf, then it remains so. Otherwise not. Which leads me to my last remark: you seem to believe that it is scanf that fills the memory with non-null chars. It is not. Those chars were already there before. If you had the feeling that some other methods fill the rest of memory with '\0', that was just an impression (a natural one, since most of the time, newly allocated memory are 0. Not because a rule says so. But because that is the most frequent byte to be found in random area of memory. That is why uninitialized variables bugs are so painful: they occur only from times to times, because very often uninitialized variables are 0, just by chance, but still they are)
The easiest way to create a zeroed array is to use calloc.
Try replacing
char string1 [100];
with
char *string1=calloc(1,100);

What is the point of assigning the size of a string?

For an instance if I store ABCDE from scanf function, the later printf function gives me ABCDE as output. So what is the point of assigning the size of the string(Here 4).
#include <stdio.h>
int main() {
int c[4];
printf("Enter your name:");
scanf("%s",c);
printf("Your Name is:%s",c);
return 0;
}
I'll start with, don't use int array to store strings!
int c[4] allocates an array of 4 integers. An int is typically 4 bytes, so usually this would be 16 bytes (but might be 8 or 32 or something else on some platforms).
Then, you use this allocation first to read characters with scanf. If you enter ABCDE, it uses up 6 characters (there is an extra 0 byte at the end of the string marking the end, which needs space too), which happens to fit into the memory reserved for array of 4 integers. Now you could be really unlucky and have a platform where int has a so called "trap representation", which would cause your program to crash. But, if you are not writing the code for some very exotic device, there won't be. Now it just so happens, that this code is going to work, for the same reason memcpy is going to work: char type is special in C, and allows copying bytes to and from different types.
Same special treatment happens, when you print the int[4] array with printf using %s format. It works, because char is special.
This also demonstrates how very unsafe scanf and printf are. They happily accept c you give them, and assume it is a char array with valid size and data.
But, don't do this. If you want to store a string, use char array. Correct code for this would be:
#include <stdio.h>
int main() {
char c[16]; // fits 15 characters plus terminating 0
printf("Enter your name:");
int items = scanf("%15s",c); // note: added maximum characters
// scanf returns number of items read successfully, *always* check that!
if (items != 1) {
return 1; // exit with error, maybe add printing error message
}
printf("Your Name is: %s\n",c); // note added newline, just as an example
return 0;
}
The size of an array must be defined while declaring a C String variable because it is used to calculate how many characters are going to be stored inside the string variable and thus how much memory will be reserved for your string. If you exceed that amount the result is undefined behavior.
You have used int c , not char c . In C, a char is only 1 byte long, while a int is 4 bytes. That's why you didn't face any issues.
(Simplifying a fair amount)
When you initialize that array of length 4, C goes and finds a free spot in memory that has enough consecutive space to store 4 integers. But if you try to set c[4] to something, C will write that thing in the memory just after your array. Who knows what’s there? That might not be free, so you might be overwriting something important (generally bad). Also, if you do some stuff, and then come back, something else might’ve used that memory slot (properly) and overwritten your data, replacing it with bizarre, unrelated, and useless (to you) data.
In C language the last of the string is '\0'.
If you print with the below function, you can see the last character of the string.
scanf("%s", c); add the last character, '\0'.
So, if you use another function, getc, getch .., you should consider adding the laster character by yourself.
#include<stdio.h>
#include<string.h>
int main(){
char c[4+1]; // You should add +1 for the '\0' character.
char *p;
int len;
printf("Enter your name:");
scanf("%s", c);
len = strlen(c);
printf("Your Name is:%s (%d)\n", c, len);
p = c;
do {
printf("%x\n", *(p++));
} while((len--)+1);
return 0;
}
Enter your name:1234
Your Name is:1234 (4)
31
32
33
34
0 --> last character added by scanf("%s);
ffffffae --> garbage

C - Print ASCII Value for Each Character in a String

I'm new to C and I'm trying to write a program that prints the ASCII value for every letter in a name that the user enters. I attempted to store the letters in an array and try to print each ASCII value and letter of the name separately but, for some reason, it only prints the value of the first letter.
For example, if I write "Anna" it just prints 65 and not the values for the other letters in the name. I think it has something to do with my sizeof(name)/sizeof(char) part of the for loop, because when I print it separately, it only prints out 1.
I can't figure out how to fix it:
#include <stdio.h>
int main(){
int e;
char name[] = "";
printf("Enter a name : \n");
scanf("%c",&name);
for(int i = 0; i < (sizeof(name)/sizeof(char)); i++){
e = name[i];
printf("The ASCII value of the letter %c is : %d \n",name[i],e);
}
int n = (sizeof(name)/sizeof(char));
printf("%d", n);
}
Here's a corrected, annotated version:
#include <stdio.h>
#include <string.h>
int main() {
int e;
char name[100] = ""; // Allow for up to 100 characters
printf("Enter a name : \n");
// scanf("%c", &name); // %c reads a single character
scanf("%99s", name); // Use %s to read a string! %99s to limit input size!
// for (int i = 0; i < (sizeof(name) / sizeof(char)); i++) { // sizeof(name) / sizeof(char) is a fixed value!
size_t len = strlen(name); // Use this library function to get string length
for (size_t i = 0; i < len; i++) { // Saves calculating each time!
e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
printf("\n Name length = %zu\n", strlen(name)); // Given length!
int n = (sizeof(name) / sizeof(char)); // As noted above, this will be ...
printf("%d", n); // ... a fixed value (100, as it stands).
return 0; // ALWAYS return an integer from main!
}
But also read the comments given in your question!
This is a rather long answer, feel free to skip to the end for the code example.
First of all, by initialising a char array with unspecified length, you are making that array have length 1 (it only contains the empty string). The key issue here is that arrays in C are fixed size, so name will not grow larger.
Second, the format specifier %c causes scanf to only ever read one byte. This means that even if you had made a larger array, you would only be reading one byte to it anyway.
The parameter you're giving to scanf is erroneous, but accidentally works - you're passing a pointer to an array when it expects a pointer to char. It works because the pointer to the array points at the first element of the array. Luckily this is an easy fix, an array of a type can be passed to a function expecting a pointer to that type - it is said to "decay" to a pointer. So you could just pass name instead.
As a result of these two actions, you now have a situation where name is of length 1, and you have read exactly one byte into it. The next issue is sizeof(name)/sizeof(char) - this will always equal 1 in your program. sizeof char is defined to always equal 1, so using it as a divisor causes no effect, and we already know sizeof name is equal to 1. This means your for loop will only ever read one byte from the array. For the exact same reason n is equal to 1. This is not erroneous per se, it's just probably not what you expected.
The solution to this can be done in a couple of ways, but I'll show one. First of all, you don't want to initialize name as you do, because it always creates an array of size 1. Instead you want to manually specify a larger size for the array, for instance 100 bytes (of which the last one will be dedicated to the terminating null byte).
char name[100];
/* You might want to zero out the array too by eg. using memset. It's not
necessary in this case, but arrays are allowed to contain anything unless
and until you replace their contents.
Parameters are target, byte to fill it with, and amount of bytes to fill */
memset(name, 0, sizeof(name));
Second, you don't necessarily want to use scanf at all if you're reading just a byte string from standard input instead of a more complex formatted string. You could eg. use fgets to read an entire line from standard input, though that also includes the newline character, which we'll have to strip.
/* The parameters are target to write to, bytes to write, and file to read from.
fgets writes a null terminator automatically after the string, so we will
read at most sizeof(name) - 1 bytes.
*/
fgets(name, sizeof(name), stdin);
Now you've read the name to memory. But the size of name the array hasn't changed, so if you used the rest of the code as is you would get a lot of messages saying The ASCII value of the letter is : 0. To get the meaningful length of the string, we'll use strlen.
NOTE: strlen is generally unsafe to use on arbitrary strings that might not be properly null-terminated as it will keep reading until it finds a zero byte, but we only get a portable bounds-checked version strnlen_s in C11. In this case we also know that the string is null-terminated, because fgets deals with that.
/* size_t is a large, unsigned integer type big enough to contain the
theoretical maximum size of an object, so size functions often return
size_t.
strlen counts the amount of bytes before the first null (0) byte */
size_t n = strlen(name);
Now that we have the length of the string, we can check if the last byte is the newline character, and remove it if so.
/* Assuming every line ends with a newline, we can simply zero out the last
byte if it's '\n' */
if (name[n - 1] == '\n') {
name[n - 1] = '\0';
/* The string is now 1 byte shorter, because we removed the newline.
We don't need to calculate strlen again, we can just do it manually. */
--n;
}
The loop looks quite similar, as it was mostly fine to begin with. Mostly, we want to avoid issues that can arise from comparing a signed int and an unsigned size_t, so we'll also make i be type size_t.
for (size_t i = 0; i < n; i++) {
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
Putting it all together, we get
#include <stdio.h>
#include <string.h>
int main() {
char name[100];
memset(name, 0, sizeof(name));
printf("Enter a name : \n");
fgets(name, sizeof(name), stdin);
size_t n = strlen(name);
if (n > 0 && name[n - 1] == '\n') {
name[n - 1] = '\0';
--n;
}
for (size_t i = 0; i < n; i++){
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
/* To correctly print a size_t, use %zu */
printf("%zu\n", n);
/* In C99 main implicitly returns 0 if you don't add a return value
yourself, but it's a good habit to remember to return from functions. */
return 0;
}
Which should work pretty much as expected.
Additional notes:
This code should be valid C99, but I believe it's not valid C89. If you need to write to the older standard, there are several things you need to do differently. Fortunately, your compiler should warn you about those issues if you tell it which standard you want to use. C99 is probably the default these days, but older code still exists.
It's a bit inflexible to be reading strings into fixed-size buffers like this, so in a real situation you might want to have a way of dynamically increasing the size of the buffer as necessary. This will probably require you to use C's manual memory management functionality like malloc and realloc, which aren't particularly difficult but take greater care to avoid issues like memory leaks.
It's not guaranteed the strings you're reading are in any specific encoding, and C strings aren't really ideal for handling text that isn't encoded in a single-byte encoding. There is support for "wide character strings" but probably more often you'll be handling char strings containing UTF-8 where a single codepoint might be multiple bytes, and might not even represent an individual letter as such. In a more general-purpose program, you should keep this in mind.
If we need write a code to get ASCII values of all elements in a string, then we need to use "%d" instead of "%c". By doing this %d takes the corresponding ascii value of the following character.
If we need to only print the ascii value of each character in the string. Then this code will work:
#include <stdio.h>
char str[100];
int x;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
printf("%d\n",str[x]);
}
}
To store all corresponding ASCII value of character in a new variable, we need to declare an integer variable and assign it to character. By this way the integer variable stores ascii value of character. The code is:
#include <stdio.h>
char str[100];
int x,ascii;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
ascii=str[x];
printf("%d\n",ascii);
}
}
I hope this answer helped you.....😊

String terminator issues

If I type in this code, it compiles and runs (I use GCC)
#include<stdio.h>
int main()
{
char sentence[8]="September";
printf("The size of the array is %d \n",sizeof(sentence));
printf("The array is %s \n",sentence);
}
and gives the output
The size of the array is 8
The array is Septembe
How is this working? A string terminator is needed for C to know that the string has ended. How is the array worth 8 bytes of space and knows where to stop?
By passing a non-NUL-terminated string to printf("%s"), you're invoking undefined behavior.
By its very nature, the result is undefined. It may seemingly "work" (like you're seeing).
As others have explained, what's probably happening is that there happens to be a zero byte after your string, which stops printf from going further. However, if you were to add more stuff around that variable, you'd probably see different behavior:
#include<stdio.h>
int main(void)
{
char sentence[8] = "September"; // NOT NUL TERMINATED!
char stuff[] = "This way is better";
printf("%s\n", sentence); // Will overrun sentence
return 0;
}

why does this simple code gives not work at times????then when i restart my code blocks it does work at times

#include <stdio.h>
#include <stdlib.h>
main()
{
char *a,*b,*c={0};
int i=0,j=0;
a=(char *)malloc(20*sizeof(char));
b=(char *)malloc(20*sizeof(char));
c=(char *)malloc(20*sizeof(char));
printf("Enter two strings:");
gets(a);
gets(b);
while(a[i]!=NULL)
{
c[i]=a[i];
i++;
}
while(b[j]!=NULL)
{
c[i]=b[j];
i++;
j++;
}
printf("The concated string is %s",c);
}
this is crazy........i spend one whole night it didn't work and then next night it suddenly works perfectly....i'm confused
There are many things wrong with your code.
Not all of them matter if all you care about is getting the code to work.
However, I have tried here to show you different misconceptions that are clear from your code, and show you how to code it better.
You are misunderstanding what NULL means. a NULL pointer doesn't point at anything
Strings are terminated with '\0' which is an ASCII NUL, not the same thing, though both use the value 0.
char* s = "hello";
The above string is actually 6 characters long. 5 bytes for the hello, 1 for the '\0' that is stuck at the end. Incidentally, this means that you can only have strings up to 19 characters long because you need to reserve one byte for the terminal '\0'
char* r = NULL;
The pointer r is pointing at nothing. There is no '\0' there, and if you attempt to look at r[0], you will crash.
As Ooga pointed out, you missed terminating with '\0' which is going to create random errors because your printf will keep going to try to print until the first zero byte it finds. Whether you crash on any particular run is a matter of luck. Zeros are common, so usually you will stop before you crash, but you will probably print out some junk after the string.
Personally, I would rather crash than have the program randomly print out the wrong thing. At least when you crash, you know something is wrong and can fix it.
You also seem to have forgotten to free the memory you malloc.
If you are going to use malloc, you should use free at the end:
int* a = malloc(20);
...
free(a);
You also are only mallocing 20 characters. If you go over that, you will do horrible things in memory. 20 seems too short, you will have only 19 characters plus the null on the end to play with but if you do have 20 characters each in a and b, you would need 40 characters in c.
If this is an assignment to use malloc, then use it, but you should free when you are done. If you don't have to use malloc, this example does not show a reason for using it since you are allocating a small, constant amount of memory.
You are initializing c:
char* c = {0};
In a way that makes no sense.
The {0} is an array with a single zero value. c is pointing to it, but then you immediately point it at something else and never look at your little array again.
You probably mean that C is pointing to nothing at first.
That would be:
char* c = NULL;
but then you are immediately wiping out the null, so why initialize c, but not a and b?
As a general rule, you should not declare values and initialize them later. You can always do something stupid and use them before they are initialized. Instead, initialize as you declared the:
int* a = malloc(20);
int* b = malloc(20);
int* c = malloc(40);
Incidentally, the size of a char is by definition 1, so:
20* sizeof(char)
is the same as 20.
You probably saw an example like:
20 * sizeof(int)
Since sizeof(int) which is not 1 the above does something. Typically sizeof(int) is 4 bytes, so the above would allocate 80 bytes.
gets is unsafe, since it doesn't say how long the buffer is
ALWAYS use fgets instead of gets. (see below).
Many computers have been hacked using this bug (see http://en.wikipedia.org/wiki/Robert_Tappan_Morris)
Still, since malloc is not really needed, in your code, you really should write:
enum { SIZE = 128 };
char a[SIZE];
fgets(a, SIZE, STDIN);
char b[SIZE];
fgets(b, SIZE, STDIN);
char c[SIZE*2];
int i;
int j = 0;
for (i = 0; a[i] != '\0' && i < 127; i++)
c[j++] = a[i];
for (i; b[i] != '\0' && i < 127; i++)
c[j++] = a[i];
c[j] = '\0';
...
Last, I don't know if you are learning C or C++. I will simply point out that this kind of programming is a lot easier in C++ where a lot of the work is done for you. You can first get concatenation done the easy way, then learn all the pointer manipulation which is harder.
#include <string>
#include <iostream>
using namespace std;
int main() {
string a,b,c;
getline(cin, a); // read in a line
getline(cin, b);
c = a + b;
cout << c;
}
Of course, you still need to learn this low-level pointer stuff to be a sophisticated programmer in C++, but if the purpose is just to read in and concatenate lines, C++ makes it a lot easier.
You are not properly null-terminating c. Add this before the printf:
c[i] = '\0';
Leaving out null-termination will seem to work correctly if the char at i happens to be 0, but you need to set it to be sure.
The string c is not being terminated with a null char, this means printf does not know where to stop and will likely segfault your program when it overruns. The reason you may be getting sporadic success is that there is a random chance the malloced area has been pre zeroed when you allocate it, if this is the case it will succeed as a null char is represented as a literal 0 byte.
there are two solutions available to you here, first you could manually terminate the string with a null char as so:
c[i] = '\0';
Second you can use calloc instead of malloc, it guarantees the memory is always pre zeroed.
As a side note you should likely add some length checking to your code to ensure c will not overflow if A and B are both over 10. (or just make c 40 long)
I hope this helps.

Resources