I'm trying to create a function that get a string, taking char by char:
char * GetString (int dim) // dim is the size of the string
{
char c, *S;
int i = 0;
S = (char*)malloc(dim*(sizeof(char));
while ((c=getchar() != '\n') && (i < dim) && (c != EOF))
{
S[i] = c;
i++;
}
S[i] = '/0';
return S;
}
The problem is when i try to use a "printf" in this function, trying to see if the input was taken correctly, it shows me strange characters, not the ones i inserted. I don't know what i'm missing.
Thanks very much.
This should be a backslash:
S[i] = '\0';
Make sure your compiler warnings are turned on and you're paying attention to them. '/0' is a non-standard multi-character integer literal.
Backslash zero '\0' is the C string NUL-terminator you're after.
Also, in the case where your input is larger than dim, you are overrunning your buffer, writing one byte more than you allocated. I would suggest allocating dim+1 bytes.
Finally, there's no point in multiplying by sizeof(char) - it is 1 by definition.
P.S. Now is an excellent time to learn how to use a debugger. If you're using GNU tools: gcc -Wall -Werror main.c then gdb a.out, and type r to run.
This '/0' is a character constant which value is implementation defined. So you have to replace it with escape character '\0'.
Also you have to allocate dim + 1 bytes if you want to append exactly dim characters with the terminating zero.
The function can look like
char * GetString( int dim )
{
char *s;
int i;
s = ( char* )malloc( ( dim + 1 ) *( sizeof( char ) );
i = 0;
while ( i < dim && ( ( c = getchar() ) != '\n') && ( c != EOF ) )
{
s[i++] = c;
}
s[i] = '\0';
return s;
}
Thanks to Vlads from Moscow for the right snippets. The problem was here:
while (c = getchar() != '\n')
It's wrong, the right way:
while ((c=getchar()) != '\n')
The code had an amazingly simple problem: you missed parentheses around c=getchar(). Try ((c=getchar()) != '\n') instead of (c=getchar() != '\n')
The code has other problems also, like using /0 instead of \0
Here is the rectified code:
#include <stdio.h>
#include <stdlib.h>
char * GetString (int dim) // dim is the size of the string
{
char c, *S;
int i = 0;
S = (char*)malloc(dim*(sizeof(char)));
while (((c=getchar()) != '\n') && (i < dim) && (c != EOF))
{
S[i] = c;
i++;
}
S[i] = '\0';
return S;
}
int main()
{
char *s;
s = GetString(10);
printf("%s\n", s);
free(s);
return 0;
}
Related
** I understood how the function getline is working, it simply assigning value in each s[] array address which gets stored into the char line[] array because function argument has local scope there is no conflict due to the use of different array names unless it shares the same data type, But my concern is that why checker function has no effect on an actual string. correct me if the above understanding is wrong and why the checker function not working.**
the expected result was, getting string without trailing blanks and tabs like (hello World) but instead of that actual input that I typed in is printed which is ('\s'hello World'\t').
#define MAXLINE 50
int getline(char line[], int max);
int checker(char line[]);
int main(){
char line[MAXLINE];
while( getline(line, MAXLINE) > 0 )
if( checker(line) > 0 )
printf("%s",line);
return 0;
}
int getline(char s[],int lim){
int c,i,j;
j=0;
for(i=0; (c=getchar()) != EOF && c != '\n';i++){
if(i < lim-1){
s[j]=c;
++j;
}
}
if(c == '\n'){
s[j] = c;
++j;
++i;
}
s[j] = '\0';
return i;
}
int checker(char s[]){
int i;
i=0;
while(s[i] != '\n' )
++i;
--i;
while(i >= 0 && (s[i] == ' ' || s[i] == '\t') )
i++;
if( i >= 0){
++i;
s[i] = '\n';
++i;
s[i] = '\0';
}
return i;
}
If you are trying to trim trailing blanks and tabs from your string, try changing the contents of the second while loop in checker() to contain i-- rather than i++.
Since checker() is intended to change the string, perhaps a different name would be better. The word check does not usually imply modification. A well chosen name is a great help to the next person who encounters your code.
The bug seems to be here:
while(i >= 0 && (s[i] == ' ' || s[i] == '\t') )
i++;
^^^^
This shall probably be i--;
That said... Your function isn't secure. It lacks some checks to prevent access outside the char array.
For instance:
What happens if the input string has no '\n' ?
What happens if the input string is a space followed by '\n' ?
Also the getline function has a problem. If the input is longer than lim, the code will do s[lim] = '\0'; which is out of bounds.
What I am trying to code is, if I input camelcase, it should just print out camelcase, but if there contains any uppercase, for example, if I input camelCase, it should print out camel_case.
The below is the one I am working on but the problem is, if I input, camelCase, it prints out camel_ase.
Can someone please tell me the reason and how to fix it?
#include <stdio.h>
#include <ctype.h>
int main() {
char ch;
char input[100];
int i = 0;
while ((ch = getchar()) != EOF) {
input[i] = ch;
if (isupper(input[i])) {
input[i] = '_';
//input[i+1] = tolower(ch);
} else {
input[i] = ch;
}
printf("%c", input[i]);
i++;
}
}
First look at your code and think about what happens when someone enters a word longer than 100 characters -> undefined behavior. If you use a buffer for input, you always have to add checks so you don't overflow this buffer.
But then, as you directly print the characters, why do you need a buffer at all? It's completely unnecessary with the approach you show. Try this:
#include <stdio.h>
#include <ctype.h>
int main()
{
int ch;
int firstChar = 1; // needed to also accept PascalCase
while((ch = getchar())!= EOF)
{
if(isupper(ch))
{
if (!firstChar) putchar('_');
putchar(tolower(ch));
} else
{
putchar(ch);
}
firstChar = 0;
}
}
Side note: I changed the type of ch to int. This is because getchar() returns an int, putchar(), isupper() and islower() take an int and they all use a value of an unsigned char, or EOF. As char is allowed to be signed, on a platform with signed char, you would get undefined behavior calling these functions with a negative char. I know, this is a bit complicated. Another way around this issue is to always cast your char to unsigned char when calling a function that takes the value of an unsigned char as an int.
As you use a buffer, and it's useless right now, you might be interested there is a possible solution making good use of a buffer: Read and write a whole line at a time. This is slightly more efficient than calling a function for every single character. Here's an example doing that:
#include <stdio.h>
static size_t toSnakeCase(char *out, size_t outSize, const char *in)
{
const char *inp = in;
size_t n = 0;
while (n < outSize - 1 && *inp)
{
if (*inp >= 'A' && *inp <= 'Z')
{
if (n > outSize - 3)
{
out[n++] = 0;
return n;
}
out[n++] = '_';
out[n++] = *inp + ('a' - 'A');
}
else
{
out[n++] = *inp;
}
++inp;
}
out[n++] = 0;
return n;
}
int main(void)
{
char inbuf[512];
char outbuf[1024]; // twice the lenght of the input is upper bound
while (fgets(inbuf, 512, stdin))
{
toSnakeCase(outbuf, 1024, inbuf);
fputs(outbuf, stdout);
}
return 0;
}
This version also avoids isupper() and tolower(), but sacrifices portability. It only works if the character encoding has letters in sequence and has the uppercase letters before the lowercase letters. For ASCII, these assumptions hold. Be aware that what is considered an (uppercase) letter could also depend on the locale. The program above only works for letters A-Z as in the english language.
I don't know exactly how to code in C but I think you should do something like this.
if(isupper(input[i]))
{
input[i] = tolower(ch);
printf("_");
} else
{
input[i] = ch;
}
There are two problems in your code:
You insert one character in each branch of if, while one of them is supposed to insert two characters, and
You print characters as you go, but the first branch is supposed to print both _ and ch.
You can fix this by incrementing i on insertion with i++, and by printing the entire word at the end:
int ch; // <<== Has to be int, not char
char input[100];
int i = 0;
while((ch = getchar())!= EOF && (i < sizeof(input)-1)) {
if(isupper(ch)) {
if (i != 0) {
input[i++] = '_';
}
ch = tolower(ch);
}
input[i++] = ch;
}
input[i] = '\0'; // Null-terminate the string
printf("%s\n", input);
Demo.
There are multiple problems in your code:
ch is defined as a char: you cannot properly test for end of file if c is not defined as an int. getc() can return all values of type unsigned char plus the special value EOF, which is negative. Define ch as int.
You store the byte into the array input and use isupper(input[i]). isupper() is only defined for values returned by getc(), not for potentially negative values of the char type if this type is signed on the target system. Use isupper(ch) or isupper((unsigned char)input[i]).
You do not check if i is small enough before storing bytes to input[i], causing a potential buffer overflow. Note that it is not necessary to store the characters into an array for your problem.
You should insert the '_' in the array and the character converted to lowercase. This is your principal problem.
Whether you want Main to be converted to _main, main or left as Main is a question of specification.
Here is a simpler version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (isupper(c)) {
putchar('_');
putchar(tolower(c));
} else {
putchar(c);
}
}
return 0;
}
To output the entered characters in the form as you showed there is no need to use an array. The program can look the following way
#include <stdio.h>
#include <ctype.h>
int main( void )
{
int c;
while ((c = getchar()) != EOF && c != '\n')
{
if (isupper(c))
{
putchar('_');
c = tolower(c);
}
putchar(c);
}
putchar('\n');
return 0;
}
If you want to use a character array you should reserve one its element for the terminating zero if you want that the array would contain a string.
In this case the program can look like
#include <stdio.h>
#include <ctype.h>
int main( void )
{
char input[100];
const size_t N = sizeof(input) / sizeof(*input);
int c;
size_t i = 0;
while ( i + 1 < N && (c = getchar()) != EOF && c != '\n')
{
if (isupper(c))
{
input[i++] = '_';
c = tolower(c);
}
if ( i + 1 != N ) input[i++] = c;
}
input[i] = '\0';
puts(input);
return 0;
}
This should be relatively simple.
I've got a string/character pointer that looks like this
" 1001"
Notice the space before the 1. How do I remove this space while still retaining the integer after it (not converting to characters or something)?
The simplest answer is:
char *str = " 1001";
char *p = str+1; // this is what you need
If the space is at the beginning of string.You also can do it.
char *str = " 1001";
char c[5];
sscanf(str,"%s",c);
printf("%s\n",c);
%s will ignore the first space at the beginning of the buffer.
One solution to this is found here: How to remove all occurrences of a given character from string in C?
I recommend removing the empty space character or any character by creating a new string with the characters you want.
You don't seem to be allocating memory so you don't have to worry about letting the old string die.
If it is a character pointer, I believe
char* new = &(old++);
Should do the trick
I'm guessing your reading in a String representation of an integer from stdin and want to get rid of the white space? If you can't use the other tricks above with pointers and actually need to modify the memory, use the following functions.
You can also use sprintf to get the job done.
I'm sure there is more efficient ways to trim the string. Here is just an example.
void trim(unsigned char * str)
{
trim_front(str);
trim_back(str);
}
void trim_front(unsigned char * str)
{
int i = 0;
int index = 0;
int length = strlen(str);
while(index < length && (str[index] == ' ' || str[index] == '\t' || str[index] == '\n'))
{
index++;
}
while(index < length)
{
str[i] = str[index];
i++;
index++;
}
}
void trim_back(unsigned char * str)
{
int i;
for(i = 0; str[i] != ' ' && str[i] != '\n' && str[i] != '\t' && str[i] != '\0'; i++);
str[i] = '\0';
}
I am writing C program that reads input from the standard input a line of characters.Then output the line of characters in reverse order.
it doesn't print reversed array, instead it prints the regular array.
Can anyone help me?
What am I doing wrong?
main()
{
int count;
int MAX_SIZE = 20;
char c;
char arr[MAX_SIZE];
char revArr[MAX_SIZE];
while(c != EOF)
{
count = 0;
c = getchar();
arr[count++] = c;
getReverse(revArr, arr);
printf("%s", revArr);
if (c == '\n')
{
printf("\n");
count = 0;
}
}
}
void getReverse(char dest[], char src[])
{
int i, j, n = sizeof(src);
for (i = n - 1, j = 0; i >= 0; i--)
{
j = 0;
dest[j] = src[i];
j++;
}
}
You have quite a few problems in there. The first is that there is no prototype in scope for getReverse() when you use it in main(). You should either provide a prototype or just move getReverse() to above main() so that main() knows about it.
The second is the fact that you're trying to reverse the string after every character being entered, and that your input method is not quite right (it checks an indeterminate c before ever getting a character). It would be better as something like this:
count = 0;
c = getchar();
while (c != EOF) {
arr[count++] = c;
c = getchar();
}
arr[count] = '\0';
That will get you a proper C string albeit one with a newline on the end, and even possibly a multi-line string, which doesn't match your specs ("reads input from the standard input a line of characters"). If you want a newline or file-end to terminate input, you can use this instead:
count = 0;
c = getchar();
while ((c != '\n') && (c != EOF)) {
arr[count++] = c;
c = getchar();
}
arr[count] = '\0';
And, on top of that, c should actually be an int, not a char, because it has to be able to store every possible character plus the EOF marker.
Your getReverse() function also has problems, mainly due to the fact it's not putting an end-string marker at the end of the array but also because it uses the wrong size (sizeof rather than strlen) and because it appears to re-initialise j every time through the loop. In any case, it can be greatly simplified:
void getReverse (char *dest, char *src) {
int i = strlen(src) - 1, j = 0;
while (i >= 0) {
dest[j] = src[i];
j++;
i--;
}
dest[j] = '\0';
}
or, once you're a proficient coder:
void getReverse (char *dest, char *src) {
int i = strlen(src) - 1, j = 0;
while (i >= 0)
dest[j++] = src[i--];
dest[j] = '\0';
}
If you need a main program which gives you reversed characters for each line, you can do that with something like this:
int main (void) {
int count;
int MAX_SIZE = 20;
int c;
char arr[MAX_SIZE];
char revArr[MAX_SIZE];
c = getchar();
count = 0;
while(c != EOF) {
if (c != '\n') {
arr[count++] = c;
c = getchar();
continue;
}
arr[count] = '\0';
getReverse(revArr, arr);
printf("'%s' => '%s'\n", arr, revArr);
count = 0;
c = getchar();
}
return 0;
}
which, on a sample run, shows:
pax> ./testprog
hello
'hello' => 'olleh'
goodbye
'goodbye' => 'eybdoog'
a man a plan a canal panama
'a man a plan a canal panama' => 'amanap lanac a nalp a nam a'
Your 'count' variable goes to 0 every time the while loop runs.
Count is initialised to 0 everytime the loop is entered
you are sending the array with each character for reversal which is not a very bright thing to do but won't create problems. Rather, first store all the characters in the array and send it once to the getreverse function after the array is complete.
sizeof(src) will not give the number of characters. How about you send i after the loop was terminated in main as a parameter too. Ofcourse there are many ways and various function but since it seems like you are in the initial stages, you can try up strlen and other such functions.
you have initialised j to 0 in the for loop but again, specifying it INSIDE the loop will initialise the value everytime its run from the top hence j ends up not incrmenting. So remore the j=0 and i=0 from INSIDE the loop since you only need to get it initialised once.
check this out
#include <stdio.h>
#include <ctype.h>
void getReverse(char dest[], char src[], int count);
int main()
{
// *always* initialize variables
int count = 0;
const int MaxLen = 20; // max length string, leave upper case names for MACROS
const int MaxSize = MaxLen + 1; // add one for ending \0
int c = '\0';
char arr[MaxSize] = {0};
char revArr[MaxSize] = {0};
// first collect characters to be reversed
// note that input is buffered so user could enter more than MAX_SIZE
do
{
c = fgetc(stdin);
if ( c != EOF && (isalpha(c) || isdigit(c))) // only consider "proper" characters
{
arr[count++] = (char)c;
}
}
while(c != EOF && c != '\n' && count < MaxLen); // EOF or Newline or MaxLen
getReverse( revArr, arr, count );
printf("%s\n", revArr);
return 0;
}
void getReverse(char dest[], char src[], int count)
{
int i = count - 1;
int j = 0;
while ( i > -1 )
{
dest[j++] = src[i--];
}
}
Dealing with strings is a rich source of bugs in C, because even simple operations like copying and modifying require thinking about issues of allocation and storage. This problem though can be simplified considerably by thinking of the input and output not as strings but as streams of characters, and relying on recursion and local storage to handle all allocation.
The following is a complete program that will read one line of standard input and print its reverse to standard output, with the length of the input limited only by the growth of the stack:
int florb (int c) { return c == '\n' ? c : putchar(florb(getchar())), c; }
main() { florb('-'); }
..or check this
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
char *my_rev(const char *source);
int main(void)
{
char *stringA;
stringA = malloc(MAX); /* memory allocation for 100 characters */
if(stringA == NULL) /* if malloc returns NULL error msg is printed and program exits */
{
fprintf(stdout, "Out of memory error\n");
exit(1);
}
else
{
fprintf(stdout, "Type a string:\n");
fgets(stringA, MAX, stdin);
my_rev(stringA);
}
return 0;
}
char *my_rev(const char *source) /* const makes sure that function does not modify the value pointed to by source pointer */
{
int len = 0; /* first function calculates the length of the string */
while(*source != '\n') /* fgets preserves terminating newline, that's why \n is used instead of \0 */
{
len++;
*source++;
}
len--; /* length calculation includes newline, so length is subtracted by one */
*source--; /* pointer moved to point to last character instead of \n */
int b;
for(b = len; b >= 0; b--) /* for loop prints string in reverse order */
{
fprintf(stdout, "%c", *source);
len--;
*source--;
}
return;
}
Output looks like this:
Type a string:
writing about C programming
gnimmargorp C tuoba gnitirw
I bought a C book called "The C (ANSI C) PROGRAMMING LANGUAGE" to try and teach myself, well C. Anyhow, the book includes a lot of examples and practices to follow across the chapters, which is nice.
Anyhow, the code below is my answer to the books "count the longest line type of program", the authors are using a for-loop in the function getLine(char s[], int lim). Which allows for a proper display of the string line inside the main() function. However using while won't work - for a reason that is for me unknown, perhaps someone might shed a light on the situation to what my error is.
EDIT: To summarize the above. printf("%s\n", line); won't display anything.
Thankful for any help.
#include <stdio.h>
#define MAXLINE 1024
getLine(char s[], int lim) {
int c, i = 0;
while((c = getchar()) != EOF && c != '\n' && i < lim) {
s[++i] = c;
}
if(c == '\n' && i != 0) {
s[++i] = c;
s[++i] = '\0';
}
return i;
}
main(void) {
int max = 0, len;
char line[MAXLINE], longest[MAXLINE];
while((len = getLine(line,MAXLINE)) > 0) {
if(len > max) {
max = len;
printf("%s\n", line);
}
}
return 0;
}
You have a number of serious bugs. Here's the ones I found and how to fix them.
change your code to postincrement i to avoid leaving the first array member uninitialised, and to avoid double printing the final character:
s[++i] = c;
...
s[++i] = c;
s[++i] = '\0';
to
s[i++] = c;
...
// s[++i] = c; see below
...
s[i++] = '\0';
and fix your EOF bug:
if(c == '\n' && i != 0) {
s[++i] = c;
s[++i] = '\0';
}
to
if(c == '\n')
{
s[i++] = '\n';
}
s[i] = '\0'
Theory
When writing programs that deal with strings, arrays or other vector-type structures it is vitally important that you check the logic of your program. You should do this by hand, and run a few sample cases through it, providing sample inputs to your program and thinking out what happens.
The cases you need to run through it are:
a couple general cases
all the edge cases
In this case, your edge cases are:
first character ever is EOF
first character is 'x', second character ever is EOF
first character is '\n', second character is EOF
first character is 'x', second character is '\n', third character is EOF
a line has equal to lim characters
a line has one less than lim characters
a line has one more than lim characters
Sample edge case
first character is 'x', second character is '\n', third character is EOF
getLine(line[MAXLINE],MAXLINE])
(s := line[MAXLINE] = '!!!!!!!!!!!!!!!!!!!!!!!!...'
c := undef, i := 0
while(...)
c := 'x'
i := 1
s[1] := 'x' => s == '!x!!!!...' <- first bug found
while(...)
c := '\n'
end of while(...)
if (...)
(c== '\n' (T) && i != 0 (T)) = T
i := i + 1 = 2
s[2] = '\n' => s == '!x\n!!!!'
i := i + 1 = 3
s[3] = '\0' => s == '!x\n\0!!!' <- good, it's terminated
return i = 3
(len = i = 3) > 0) = T (the while eval)
if (...)
len (i = 3) > max = F
max = 3 <- does this make sense? is '!x\n' a line 3 chars long? perhaps. why did we keep the '\n' character? this is likely to be another bug.
printf("%s\n", line) <- oh, we are adding ANOTHER \n character? it was definitely a bug.
outputs "!x\n\n\0" <- oh, I expected it to print "x\n". we know why it didn't.
while(...)
getLine(...)
(s := line[MAXLINE] = '!x\n\0!!!!!!!!!!!!!!!!!!!...' ; <- oh, that's fun.
c := undef, i := 0
while(...)
c := EOF
while terminates without executing body
(c == '\n' && i != 0) = F
if body not executed
return i = 0
(len = i = 0 > 0) = F
while terminates
program stops.
So you see this simple process, that can be done in your head or (preferably) on paper, can show you in a matter of minutes whether your program will work or not.
By following through the other edge cases and a couple general cases you will discover the other problems in your program.
It's not clear from your question exactly what problem you're having with getLine (compile error? runtime error?), but there are a couple of bugs in your implementation. Instead of
s[++i] = something;
You should be using the postfix operator:
s[i++] = something;
The difference is that the first version stores 'something' at the index of (i+1), but the second version will store something at the index of i. In C/C++, arrays are indexed from 0, so you need to make sure it stores the character in s[0] on the first pass through your while loop, in s[1] on the second pass through, and so on. With the code you posted, s[0] is never assigned to, which will cause the printf() to print out unintialised data.
The following implementation of getline works for me:
int getLine(char s[], int lim) {
int c;
int i;
i = 0;
while((c = getchar()) != EOF && c != '\n' && i < lim) {
s[i++] = c;
}
if(c == '\n' && i != 0) {
s[i++] = c;
s[i++] = '\0';
}
return i;
}
By doing ++i instead of i++, you are not assigning anything to s[0] in getLine()!
Also, you are unnecesarilly incrementing when assigning '\0' at the end of the loop, which BTW you should always assign, so take it out from the conditional.
Also add return types to the functions (int main and int getLine)
Watch out for the overflow as well - you are assigning to s[i] at the end with a limit of i == lim thus you may be assigning to s[MAXLINE]. This would be a - wait for it - stack overflow, yup.