How to define a string length automatically in C? - c

I was trying to inverse a string in C. And I met some trouble defining the destination string.
And here are my thoughts: (I am a beginner, so my thoughts might seem laughable in your eyes...)
I define a string data type with unknown length and assign a string to it. (In my case it's str1)
I get the string length of string 1 and increment this value and assign to an integer. (l in my case. The +1 is to compensate the '\0' at the end of the string)
Use this l integer to define a new string which is the destination string. (str2 in my case.)
Use a for loop to copy from the end of str1 to the start of str2 and add a '\0' to the end of str2 to make it a string.
However, when I try to do this in visual studio 2013, it does not let me compile.
I have attached the error message and the code. (Line 15 in the error message is where I define str2 with integer l)
I tried to just put in a number (for example: 100) at the place where integer l was, and the code works.
Can you let me know what is wrong with defining a string with an integer variable and how to do it if there is a way in C, instead of just defining a long enough sting?
Thank you!
#include<stdio.h>
#include<string.h>
int main()
{
/* Reversing a string! */
int l; /* Length of str1 +1 (for the NULL character) */
char str1[] = "This is an unknown length string!";
l = strlen(str1) + 1;
char str2[l]; /* The destination string */
int i, j;
for (i = strlen(str1)-1,j=0; i < strlen(str1) && i >= 0; i--,j++)
str2[j] = str1[i];
str2[j] = '\0';
/* Display str1 and str2 */
printf("The content of str1: %s\n", str1);
printf("The content of str2: %s\n", str2);
return 0;
}

Visual studio doesn't support mix type declaration and variable length arrays. You need to declare all variables in C89 style, i.e at the beginning of your code in main. And dynamically allocate space for str2.
size_t l; /* Length of str1 +1 (for the NULL character) */
int i, j;
char str1[] = "This is an unknown length string!";
l = strlen(str1) + 1;
char *str2;
str2 = malloc(l);

An alternative that doesn't need dynamic memory allocation. It works in this scenario, but it isn't as general a solution (you couldn't sensibly use it to reverse an arbitrary number of strings of different lengths, for example, whereas you can use malloc() and free() to handle that). Your original code uses a VLA — variable length array — which is standard in C99 and optionally supported in C11.
#include <stdio.h>
int main(void)
{
/* Reversing a string! */
char str1[] = "This is an unknown length string!";
char str2[sizeof(str1)];
int len = sizeof(str1);
int i, j;
for (i = len - 2, j = 0; i >= 0; i--, j++)
str2[j] = str1[i];
str2[j] = '\0';
/* Display str1 and str2 */
printf("The content of str1: %s\n", str1);
printf("The content of str2: %s\n", str2);
return 0;
}

Related

Extra character appearing on string in C Program

I'm working on a homework problem that involves making a word search program. The letter grid and words are taken from an input file. I have the grid stored in an array and I want to turn the rows and columns into discrete strings so that I can use the strstr function on them to find a word. I wanted to test that I created a string properly and I'm finding it has two extra characters on the end of it. Why is this? BTW The size variable is equal to 5 and was used to define the dimensions of the array.
char line[size+1];
int i;
for (i = 0; i < size; i++) {
line[i] = grid[0][i];
printf("character %c \n", grid[0][i]);
}
line[size+1] = '\0';
printf("test string %s \n", line);
Here's the output including the printed word grid.
A L P H A
B O F L A
B C P Z T
B H H A E
A T X Y B
test string ALPHA'
When working with strings to denote the end of a string array the last element should always contain a null character '\0' maybe you havent assigned that because of which it is having garbage value in that place
P.S. array size is always n+1 of the actual string so that it can contain the termination character
You add the null character at an index outside of the char array. Array indexes begin with zero but you treat it like the first index is 1.
As an example, this outputs "test string ALPHAX" since the null character is added outside of the array and not in the last element:
int size = 5;
char line[size+1];
int i;
line[0] = 'A';
line[1] = 'L';
line[2] = 'P';
line[3] = 'H';
line[4] = 'A';
line[5] = 'X';
line[size+1] = '\0'; // size+1 is 6
printf("test string %s \n", line);
Change line[size+1] = '\0'; to line[size] = '\0'; in your code like below and it should work as expected.
char line[size+1];
int i;
for (i = 0; i < size; i++) {
line[i] = grid[0][i];
printf("character %c \n", grid[0][i]);
}
line[size] = '\0';
printf("test string %s \n", line);

Bug with strlen?

I'm just getting started with C and I just started trying to figure out
call by reference in functions. I have noticed an odd result in my output
when using strlen() to iterate over a string and modify its contents. In this
example the result of strlen() is 3, not including the null character,
but if I do not explicitly check for the null character (or use less than the
result of strlen() instead of less than or equals) during the for loop then
it gives a bizarre bit character in the output which I ASSUME is because of the null character?
Please help this noob to understand what is happening here.
Code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void f_test_s(char s[]);
void f_test_s2(char s[]);
int main(){
char s_test[] = "abc";
f_test_s(s_test);
f_test_s2(s_test);
puts("\nTest complete!");
return 0;
}
void f_test_s(char s[]){
puts("Test #1: ");
printf("string before: %s\n", s);
int len = strlen(s);
printf("strlen() = %d\n", len);
int i=0;
for(i=0;i<=len;i++){
if(s[i] != '\0'){
s[i]++;
}
}
printf("string after: %s\n", s);
}
void f_test_s2(char s[]){
puts("\nTest #2: ");
printf("string before: %s\n", s);
int len = strlen(s);
printf("strlen() = %d\n", len);
int i=0;
for(i=0;i<=len;i++){
s[i]++;
}
printf("string after: %s\n", s);
}
output:
Test #1:
string before: abc
strlen() = 3
string after: bcd
Test #2:
string before: bcd
strlen() = 3
string after: cde
Test complete!
If it matters I am using gcc version 7.3.0 on Ubuntu. I am definitely
not an expert with either C, gcc, or Ubuntu.
This is the problem:
for (i = 0; i <= len; i++) {
s[i]++;
}
It should be:
for (i = 0; i < len; i++) {
s[i]++;
}
s[len] is the null char (0). When you removed null char and replaced it with the value of 1, the contents of the array are now {'a', 'b', 'c', 0x1}. And when printf attempts to print s it's going to keep printing characters past the value memory address of the array until it encounters a null char. Technically this is undefined behavior.
Change this:
for (i = 0; i <= len; i++) {
to this:
for (i = 0; i < len; i++) {
since strlen() returns the length of the string. A C string is as long as the number of characters between the beginning of the string and the terminating null character (without including the terminating null character itself).
Your code invokes Undefined Behavior (UB), since you go out of bounds. Standard string functions (like printf()) depend on the NULL terminating character to mark the end of the string. Without it, they do not know when to stop . . .

How to change individual characters in string on C?

Trying to make some basic hangman code to practice learning C but I can't seem to change individual characters in the program
int main(int argc, char *argv[]) {
int length, a, x;
x = 0;
char gWord[100];
char word[100] = "horse";
length = strlen(word) - 1;
for(a = 0; a<= length; a = a + 1){
gWord[a] = "_";
printf("%s", gWord[a]);
}
printf("%s", gWord);
}
when I try to run this it just prints (null) for every time it goes through the loop. It's probably a basic fix but I'm new to C and can't find anything about it online
To print character instead of string change:
printf("%s", gWord[a]);
to:
printf("%c", gWord[a]);
but before that change also:
gWord[a] = "_";
to:
gWord[a] = '_';
The last problem is that you were assigning a string literal to a single character.
Edit:
Also as #4386427 pointed out, you never zero-terminate gWord before printing it later on with printf("%s", gWord). You should change the last line from:
printf("%s", gWord);
to:
gWord[a] = '\0';
printf("%s", gWord);
because otherwise this would very likely lead to a buffer overflow.
This line
printf("%s", gWord[a]);
Must be
printf("%c", gWord[a]);
To print a char, c is the right specifier. s is only for whole strings and takes char pointers.
Are you getting any warning message('s) when compiling your code?
Since you are learning C language, one suggestion - Never ignore any warning message given by the compiler, they are there for some reason.
Three problems in your code:
First:
Assigning string to a character:
gWord[a] = "_";
gWord is an array of 100 characters and gWord[a] is a character at location a of gWord array. Instead, you should do
gWord[a] = '_';
Second:
Using wrong format specifier for printing a character:
printf("%s", gWord[a]);
^^
For printing a character you should use %c format specifier:
printf("%c", gWord[a]);
Third:
Missed adding null terminating character at the end in gWord and printing it:
printf("%s", gWord);
In C language, strings are actually one-dimensional array of characters terminated by a null character '\0'. The %s format specifier is used for character string and by default characters are printed until the ending null character is encountered. So, you should make sure to add '\0' at the end of gWord after the for loop finishes:
gWord[a] = '\0';
Apart from these, there are couple of more things -
This statement:
length = strlen(word) - 1;
I do not see any reason of subtracting 1 from the word length. The strlen return the length of string without including the terminating null character itself. So, the strlen(word) will give output 5. Now you are subtracting 1 from this and running loop till <= length may confuse the reader of the code. You should simply do:
length = strlen(word);
for(a = 0; a < length; a = a + 1){
....
....
Also, the return type of strlen() is size_t and the size_t is an unsigned type. So, you should use the variable of type size_t to receive strlen() return value.
Last but not least, make sure to not to have any unused variables/parameters in your program. You are not using argc and argv anywhere in your program. If you are using gcc compiler then compile it with -Wall -Wextra options. You will find that compiler will report all the unused variables/parameters. So, if not using argc and argv then you should simply give void in the parameter list of main() function.
Putting these all together, you can do:
#include <stdio.h>
#include <string.h>
int main(void) {
size_t length, a;
char gWord[100];
char word[100] = "horse";
length = strlen(word);
for(a = 0; a < length; a = a + 1) {
gWord[a] = '_';
printf("%c", gWord[a]);
}
gWord[a] = '\0';
printf ("\n");
printf("%s\n", gWord);
return 0;
}
Syntactically, your code is alright #Blookey. But logically, no actually.
Let me point out 3 places which are causing the undesired behavior in your code:
gWord[a] = "_"; Observe this line. You have specified the _ in " ". In case you are unaware of this fact, each individual element of a string is a character. And each character is supposed to be given in ' ', i.e., single quotes and not double quotes.
printf("%s", gWord[a]); A similar error again. gWord[a] is a character, not a string. Hence you need to print it using the format specifier %c instead of %s which is for string instead.
A string, any string is supposed to end with a NULL, which is \0 (backslashZERO). That is what differentiates an array of characters from a string. So just add the following line once you finish loading characters into gWord[].
gWord[a] = '\0';
Here is the complete code, just with the 3 changes:
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[]) {
int length, a, x;
x = 0;
char gWord[100];
char word[100] = "horse";
length = strlen(word) - 1;
for(a = 0; a<= length; a = a + 1){
gWord[a] = '_';
printf("%c ", gWord[a]);
}
gWord[a] = '\0';
printf("\n%s", gWord);
}
Here is the OUTPUT:
_ _ _ _ _ .
_____.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main(int argc, char *argv[]) {
int length, a, x;
x = 0;
char gWord[100] = {0};
char word[100] = "horse"; /*note that if the array in place strlen +1 is not nulled before using strlen you might not get the correct result*/
length = strlen(word) - 1;/*strln will return 5, that is the letters inn the string the pointer is pointing to until the first terminator '\0'*/
for(a = 0; a<= length; a = a + 1){
gWord[a] = '_'; /* if you use "_" it will try to fit in the chars '_' and '\0' to each char slot of the array*/
printf("%c", gWord[a]); /* %s looks for a string to print while here there are single chars to print*/
}
printf("\n");/*you can print the hole string like this */
printf("%s", gWord);
return 0;/*and remember that main function should always have a return value*/
}

C: String Concatentation: Null Terminated Strings

The following code only concatenates the first string and ignores the second.. from what I gather, it has something to do with Null terminated strings. As I am new to C, this is a new concept to me. Could someone help make the code below work? That would really help me a lot in understanding this.
void concatTest();
int main()
{
concatTest();
system("PAUSE");
return 0;
}
void concatTest()
{
char string1[20], string2[20], string3[40];
char *ptr1, *ptr2, *ptr3;
ptr1 = &string1[0];
ptr2 = &string2[0];
ptr3 = &string3[0];
int i;
printf("You need to enter 2 strings.. each of which is no more than 20 chars in length: \n");
printf("Enter string #1: \n");
scanf("%s", string1);
printf("Enter string #2: \n");
scanf("%s", string2);
int len1 = strlen(string1);
int len2 = strlen(string2);
for (i = 0; i < len1; i++)
{
ptr3[i] = ptr1[i];
}
for (i = len1; i < len1 + len2; i++)
{
ptr3[i] = ptr2[i];
}
printf("%s\n", string3);
}
You are indexing ptr2[i] using i which ranges from len1 to len1 + len2. This value will probably be out of bounds of the string2 array (unless the first string you type happens to be empty).
I might write your second loop as follows:
for (i = 0; i < len2; i++) {
ptr3[len1 + i] = ptr2[i];
}
My answer will have no code, but hopefully a useful explanation.
Each string in C is terminated with \0.
If you want to concatenate two strings you need to be sure you overwrite the last character of the first string (the \0) with the first character of the 2nd string. Otherwise, no matter how long the "concatenated" string is, as soon as a \0 is encountered by a string function, it will assume the end of the string has reached.
And of course you need to be sure you have enough allocated space for the joint string.
You have to start at the first character of ptr2.
ptr3[i] = ptr2[i-len1];
from what I gather, it has something to do with Null terminated
strings.
Yes it does. Strings start at offset 0. You were starting at some random point based on the length of the fist string.

Iterating over string/strlen with umlauted characters

This is a follow-up to my previous question . I succeeded in implementing the algorithm for checking umlauted characters. The next problem comes from iterating over all characters in a string. I do this like so:
int main()
{
char* str = "Hej du kalleåäö";
printf("length of str: %d", strlen(str));
for (int i = 0; i < strlen(str); i++)
{
printf("%s ", to_morse(str[i]));
}
putchar('\n');
return 0;
}
The problem is that, because of the umlauted characters, it prints 18, and also makes the to_morse function fail (ignoring these characters). The toMorse method accepts an unsigned char as a parameter. What would be the best way to solve this? I know I can check for the umlaut character here instead of the letterNr function but I don't know if that would be a pretty/logical solution.
Normally, you'd store the string in a wchar_t and use something like ansi_strlen to get the length of it - that would give you the number of printed characters as opposed to the number of bytes you stored.
You really shouldn't be implementing UTF or Unicode or whatever multibyte character handling yourself - there are libraries for that sort of thing.
On OS X, Cocoa is a solution - note the use of "%C" in NSLog - that's an unichar (16-bit Unicode character):
#import <Cocoa/Cocoa.h>
int main()
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
NSString * input = #"Hej du kalleåäö";
printf("length of str: %d", [input length]);
int i=0;
for (i = 0; i < [input length]; i++)
{
NSLog(#"%C", [input characterAtIndex:i]);
}
[pool release];
}
You could do something like
for (int i = 0; str[i]!='\0'; ++i){
//do something with str[i]
}
Strings in C are terminated with '\0'. So it is possible to check for the end of the string like that.
EDIT: What locale are you using?
If you are going to iterating over a string, don't bother with getting its length with strlen. Just iterate until you see a NUL character:
char *p = str;
while(*p != '\0') {
printf("%c\n", *p);
++p;
}
As for the umlauted characters and such, are they UTF-8? If the string is multi-byte, you could do something like this:
size_t n = strlen(str);
char *p = str;
char *e = p + n;
while(*p != '\0') {
wchar_t wc;
int l = mbtowc(&wc, p, e - p);
if(l <= 0) break;
p += l;
/* do whatever with wc which is now in wchar_t form */
}
I honestly don't know if mbtowc will simply return -1 if it encounters a NUL in the middle of a MB character. If it does, you could just pass MB_CUR_MAX instead of e - p and do away with the strlen call. But I have a feeling this is not the case.

Resources