How to use isdisit() for a character array(string)? - c

I am using C to develop my mini project. So here isdigit() works perfectly when I use it for a char(say char a) and get the input with a scanf("%c",&a);.But it fails when I use it for a string
(say char a[5]) and get it with a scanf("%s",a);.
I expect that ,say if I give the input as 55 isdigit() it should evaluate to true and not when I give the input as say "Wd".

isdigit() is able to receive only one character as a argument.
It cannot understand character array.
If the char a[5] located in 0x38383838 on memory, isdigit(a); virtualy is isdigit(0x38383838);.
So it'll return 0 (or false).
If you want to test whether a character array is digit or not, then you should
int isdigit_array(char *a){
int num = strlen(a);
if(num == 0) return 0;
int flag_isdigit = 1;
int i;
for(i=0; i<num; i++){
flag_isdigit = flag_isdigit && isdigit(a[i]);
}
return flag_isdigit;
}

Related

Runtime error: reading uninitialized value, how can I fix it?

This function is basically just supposed to compare 2 strings and return their ASCII difference if they are different. It works perfectly fine when I compile it with the GCC compiler, but when I run it through the online compiler that is used to upload our classes homework, I get this error message:
Error near line 98: Reading an uninitialized value from address 10290
Line 98 is marked in the below code. I am not quite sure what the problem is and how I'm supposed to fix it. Does anyone have an idea?
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i]; // line 98
if (difference != 0) {
return difference;
}
}
return difference;
}
Your code can skip over EOLN, if string equals, and try to compare memory after end of lines. To fix this, you need instantly return, if both string equals, and you see EOLN char '\0' in both strings at position i. Try my fix:
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i];
if (difference != 0 || pStr1[i] == '\0') {
return difference;
}
}
return difference;
}
The problem in your code is that you fail to check the real length of the strings before indexing them. You are iterating with i from 0 to 99, but you do not check for the NUL terminator (\0) that marks the end of a string and therefore your for loop goes beyond the end of the string resulting in undefined behavior accessing memory that is not supposed to (which is what the error is telling you).
The correct way to iterate over a string, is not to loop a fixed amount of cycles: you should start from index 0 and check each character of the string in the loop condition. When you find \0, you stop. See also How to iterate over a string in C?.
Here's a correct version of your code:
int stringCompare(char *pStr1, char *pStr2) {
size_t i;
for (i = 0; pStr1[i] != '\0' && pStr2[i] != '\0'; i++) {
if (pStr1[i] != pStr2[i])
break;
}
return pStr1[i] - pStr2[i];
}
You could even write this more concisely with a simple while loop:
int stringCompare(char *pStr1, char *pStr2) {
while (*pStr1 && *pStr1 == *pStr2) {
pStr1++;
pStr2++;
}
return *pStr1 - *pStr2;
}
Of course, both the above functions expect two valid pointers to be passed as arguments. If you also want to allow invalid pointers you should check them before starting the loop (though it does not seem like you want to do that from your code).

How to check if an array of characters is a valid integer >= 1 in c?

I don't know the size of the array and using isdigit(array[i]) for every element i < sizeof(array) doesn't seem to work correctly.
I am trying to:
Check that every char is a digit.
Convert the string to int.
Check that it is > 0
int all_digits(char *string){
short i;
for(i=0; i < sizeof(string); i++){
if (!isdigit(string[i])){
//Non-digit found.
return 1;
}
}
//All of them are digits.
return 0;
}
The first part is the one that I can't get.
int n = strlen(string);
for(i=0; i < n; i++)
sizeof(pointer) is not same as sizeof(array)
You need to pass a valid string which is a null terminated string else strlen() might crash.
Edits:
Alternatively you can have
for(i=0; string[i] != '\0'; i++)
In this case you cannot get the correct length using the sizeof function.
sizeof function will give you the size of the given data type. You can use the
strlen function.
While using the strlen you have to manage the following,
Consider in your string in last there is no null value you didn't get the correct value of the string length. For this you have to send the size of that array as a another parameter or you have to place the null value in the last value of the a string.
Then you can get that easily.
In your code, string is of type char *. sizeof(string) will give you the size of a char *, not the array.
You need to pass the size of the array explicitly, using another paramter to all_digits() function and use that value in for loop condition checking.
Maybe something like this
int all_digits(char *string, int size){
short i;
for(i=0; i < size; i++){
if (!isdigit(string[i])){
//Non-digit found.
return 1;
}
}
//All of them are digits.
return 0;
}
Note: Specifically in case of a char *, a better, smaller and cleaner approach to this can be achieved using strlen() [assuming proper aguments passed], which will give you the length of the supplied string.
Simply iterate along the string, testing every character:
int all_digits(char *string){
if( *string == 0) // empty string - wrong
return 1;
for( ; *string != 0; string++) // scan the string till its end (a zero byte (char)0)
if (!isdigit(*string)) // test for a digit
return 1; // not a digit - return
return 0; // all characters are digits
}
However that only tests if the string consists of digits and does not make you any closer to determining its numerical value...

Pointers to string C

trying to write function that returns 1 if every letter in “word” appears in “s”.
for example:

containsLetters1("this_is_a_long_string","gas") returns 1
containsLetters1("this_is_a_longstring","gaz") returns 0
containsLetters1("hello","p") returns 0
Can't understand why its not right:
#include <stdio.h>
#include <string.h>
#define MAX_STRING 100
int containsLetters1(char *s, char *word)
{
int j,i, flag;
long len;
len=strlen(word);
for (i=0; i<=len; i++) {
flag=0;
for (j=0; j<MAX_STRING; j++) {
if (word==s) {
flag=1;
word++;
s++;
break;
}
s++;
}
if (flag==0) {
break;
}
}
return flag;
}
int main() {
char string1[MAX_STRING] , string2[MAX_STRING] ;
printf("Enter 2 strings for containsLetters1\n");
scanf ("%s %s", string1, string2);
printf("Return value from containsLetters1 is: %d\n",containsLetters1(string1,string2));
return 0;
Try these:
for (i=0; i < len; i++)... (use < instead of <=, since otherwise you would take one additional character);
if (word==s) should be if (*word==*s) (you compare characters stored at the pointed locations, not pointers);
Pointer s advances, but it should get back to the start of the word s, after reaching its end, i.e. s -= len after the for (j=...);
s++ after word++ is not needed, you advance the pointer by the same amount, whether or not you found a match;
flag should be initialized with 1 when declared.
Ah, that should be if(*word == *s) you need to use the indirection operator. Also as hackss said, the flag = 0; must be outside the first for() loop.
Unrelated but probably replace scanf with fgets or use scanf with length specifier For example
scanf("%99s",string1)
Things I can see wrong at first glance:
Your loop goes over MAX_STRING, it only needs to go over the length of s.
Your iteration should cover only the length of the string, but indexes start at 0 and not 1. for (i=0; i<=len; i++) is not correct.
You should also compare the contents of the pointer and not the pointers themselves. if(*word == *s)
The pointer advance logic is incorrect. Maybe treating the pointer as an array could simplify your logic.
Another unrelated point: A different algorithm is to hash the characters of string1 to a map, then check each character of the string2 and see if it is present in the map. If all characters are present then return 1 and when you encounter the first one that is not present then return 0. If you are only limited to using ASCII characters a hashing function is very easy. The longer your ASCII strings are the better the performance of the second approach.
Here is a one-liner solution, in keeping with Henry Spencer's Commandment 7 for C Programmers.
#include <string.h>
/*
* Does l contain every character that appears in r?
*
* Note degenerate cases: true if r is an empty string, even if l is empty.
*/
int contains(const char *l, const char *r)
{
return strspn(r, l) == strlen(r);
}
However, the problem statement is not about characters, but about letters. To solve the problem as literally given in the question, we must remove non-letters from the right string. For instance if r is the word error-prone, and l does not contain a hyphen, then the function returns 0, even if l contains every letter in r.
If we are allowed to modify the string r in place, then what we can do is replace every non-letter in the string with one of the letters that it does contain. (If it contains no letters, then we can just turn it into an empty string.)
void nuke_non_letters(char *r)
{
static const char *alpha =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (*r) {
size_t letter_span = strspn(r, alpha);
size_t non_letter_span = strcspn(r + letter_span, alpha);
char replace = (letter_span != 0) ? *r : 0;
memset(r + letter_span, replace, non_letter_span);
r += letter_span + non_letter_span;
}
}
This also brings up another flaw: letters can be upper and lower case. If the right string is A, and the left one contains only a lower-case a, then we have failure.
One way to fix it is to filter the characters of both strings through tolower or toupper.
A third problem is that a letter is more than just the 26 letters of the English alphabet. A modern program should work with wide characters and recognize all Unicode letters as such so that it works in any language.
By the time we deal with all that, we may well surpass the length of some of the other answers.
Extending the idea in Rajiv's answer, you might build the character map incrementally, as in containsLetters2() below.
The containsLetters1() function is a simple brute force implementation using the standard string functions. If there are N characters in the string (haystack) and M in the word (needle), it has a worst-case performance of O(N*M) when the characters of the word being looked for only appear at the very end of the searched string. The strchr(needle, needle[i]) >= &needle[i] test is an optimization if there are likely to be repeated characters in the needle; if there won't be any repeats, it is a pessimization (but it can be removed and the code still works fine).
The containsLetters2() function searches through the string (haystack) at most once and searches through the word (needle) at most once, for a worst case performance of O(N+M).
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int containsLetters1(char const *haystack, char const *needle)
{
for (int i = 0; needle[i] != '\0'; i++)
{
if (strchr(needle, needle[i]) >= &needle[i] &&
strchr(haystack, needle[i]) == 0)
return 0;
}
return 1;
}
static int containsLetters2(char const *haystack, char const *needle)
{
char map[256] = { 0 };
size_t j = 0;
for (int i = 0; needle[i] != '\0'; i++)
{
unsigned char c_needle = needle[i];
if (map[c_needle] == 0)
{
/* We don't know whether needle[i] is in the haystack yet */
unsigned char c_stack;
do
{
c_stack = haystack[j++];
if (c_stack == 0)
return 0;
map[c_stack] = 1;
} while (c_stack != c_needle);
}
}
return 1;
}
int main(void)
{
assert(containsLetters1("this_is_a_long_string","gagahats") == 1);
assert(containsLetters1("this_is_a_longstring","gaz") == 0);
assert(containsLetters1("hello","p") == 0);
assert(containsLetters2("this_is_a_long_string","gagahats") == 1);
assert(containsLetters2("this_is_a_longstring","gaz") == 0);
assert(containsLetters2("hello","p") == 0);
}
Since you can see the entire scope of the testing, this is not anything like thoroughly tested, but I believe it should work fine, regardless of how many repeats there are in the needle.

Array manipulation in C

I am like 3 weeks new at writing c code, so I am a newbie just trying some examples from a Harvard course video hosted online. I am trying to write some code that will encrypt a file based on the keyword.
The point is each letter of the alphabet will be assigned a numerical value from 0 to 25, so 'A' and 'a' will be 0, and likewise 'z' and 'Z' will be 25. If the keyword is 'abc' for example, I need to be able to convert it to its numerical form which is '012'. The approach I am trying to take (having learned nothing yet about many c functions) is to assign the alphabet list in an array. I think in the lecture he hinted at a multidimensional array but not sure how to implement that. The problem is, if the alphabet is stored as an array then the letters will be the actual values of the array and I'd need to know how to search an array based on the value, which I don't know how to do (so far I've just been returning values based on the index). I'd like some pseudo code help so I can figure this out. Thanks
In C, a char is an 8-bit integer, so, assuming your letters are in order, you can actually use the char value to get the index by using the first letter (a) as an offset:
char offset = 'a';
char value = 'b';
int index = value - offset; /* index = 1 */
This is hard to answer, not knowing what you've learned so far, but here's a hint to what I would do: the chars representing letters are bytes representing their ASCII values, and occur sequentially, from a to z and A to Z though they don't start at zero. You can cast them to ints and get the ascii values out.
Here's the pseudo code for how I'd write it:
Cast the character to a number
IF it's between the ascii values of A and Z, subtract it from A
ELSE Subtract it from the ASCII value of a or A
Output the result.
For what it's worth, I don't see an obvious solution to the problem that involves multidimensional arrays.
char '0' is the value 48
char 'A' is the value 65
char 'a' is the value 97
You said you want to learn how to search in the array:
char foo[26]; //your character array
...
...
//here is initialization of the array
for(int biz=0;biz<26;biz++)
{
foo[biz]=65+biz; // capital alphabet
}
...
...
//here is searching 1 by 1 iteration(low-yield)
char baz=67; //means we will find 'C'
for(int bar=0;bar<26;bar++)
{
if(foo[bar]==baz) {printf("we found C at the index: %i ",bar);break;}
}
//since this is a soted-array, you can use more-yield search algortihms.
Binary search algortihm(you may use on later chapters):
http://en.wikipedia.org/wiki/Binary_search_algorithm
The use of a multidimensional array is to store both the lower case and upper case alphabets in an array so that they can be mapped. An efficient way is using their ASCII code, but since you are a beginner, I guess this example will introduce you to handle for loops and multidimensional arrays, which I think is the plan of the instructor as well.
Let us first set up the array for the alphabets. We will have two rows with 26 alphabets in each row:
alphabetsEnglish[26][2] = {{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'},
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}};
Now we can map elements of both cases.
int main()
{
int c,i,j;
char word[10];
printf("Enter a word:");
scanf("%s",word);
c=strlen(word);
printf("Your word has %d letters ", c);
for (i = 0; i < c; i++) //loop for the length of your word
{
for (j = 0; j <= 25; j++) //second loop to go through your alphabet list
{
if (word[i] == alphabetsEnglish[0][j] || word[i] == alphabetsEnglish[1][j]) //check for both cases of your alphabet
{
printf("Your alphabet %c translates to %d: ", word[i], j);
}
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *conv(char* str){
static const char* table = "abcdefghijklmnopqrstuvwxyz";
int size, *ret, *p;
if(NULL==str || *str == '\0') return NULL;
size = strlen(str);
ret=p=(int*)malloc(size*sizeof(int));
while(*str){
char *pos;
pos=strchr(table, tolower(*str++));
*p++ = pos == NULL ? -1 : pos - table;
}
return ret;
}
int main(void){
char *word = "abc";
int i, size = strlen(word), *result;
result = conv(word);
for(i=0;i<size;++i){
printf("%d ", result[i]);//0 1 2
}
free(result);
return 0;
}

Parsing Integer to String C

How does one parse an integer to string(char* || char[]) in C? Is there an equivalent to the Integer.parseInt(String) method from Java in C?
If you want to convert an integer to string, try the function snprintf().
If you want to convert a string to an integer, try the function sscanf() or atoi() or atol().
To convert an int to a string:
int x = -5;
char buffer[50];
sprintf( buffer, "%d", x );
You can also do it for doubles:
double d = 3.1415;
sprintf( buffer, "%f", d );
To convert a string to an int:
int x = atoi("-43");
See http://www.acm.uiuc.edu/webmonkeys/book/c_guide/ for the documentation of these functions.
It sounds like you have a string and want to convert it to an integer, judging by the mention of parseInt, though it's not quite clear from the question...
To do this, use strtol. This function is marginally more complicated than atoi, but in return it provides a clearer indication of error conditions, because it can fill in a pointer (that the caller provides) with the address of the first character that got it confused. The caller can then examine the offending character and decide whether the string was valid or not. atoi, by contrast, just returns 0 if it got lost, which isn't always helpful -- though if you're happy with this behaviour then you might as well use it.
An example use of strtol follows. The check for error is very simple: if the first unrecognised character wasn't the '\x0' that ends the string, then the string is considered not to contain a valid int.
int ParseInt(const char *s,int *i)
{
char *ep;
long l;
l=strtol(s,&ep,0);
if(*ep!=0)
return 0;
*i=(int)l;
return 1;
}
This function fills in *i with the integer and returns 1, if the string contained a valid integer. Otherwise, it returns 0.
This is discussed in Steve Summit's C FAQs.
The Java parseInt() function parses a string to return an integer. An equivalent C function is atoi(). However, this doesn't seem to match the first part of your question. Do you want to convert from an integer to a string, or from a string to an integer?
You can also check out the atoi() function (ascii to integer) and it's relatives, atol and atoll, etc.
Also, there are functions that do the reverse as well, namely itoa() and co.
You may want to take a look at the compliant solution on this site.
You can try:
int intval;
String stringval;
//assign a value to intval here.
stringval = String(intval);
that should do the trick.
This is not an optimal solution. This is my solution given multiple restrictions, so if you had limited resources based on your course/instructor's guidelines, this may be a good fit for you.
Also note that this is a fraction of my own project implement, and I had to read in operands as well as digits, so I used getchars. Otherwise, if you only need integers and no other type of characters, I like using this:
int k;
while (scanf("%d", &k) == 1)
The rules were no specific, "advanced" C concepts: no String variables, no structs, no pointers, no methods not covered, and the only include we were allowed was #include
So with no simple method calls like atoi() available or any String variables to use, I chose to just brute force it.
1: read chars in using getchar (fgets was banned). return 1 (exit status 1) if
there is an invalid character. For your problem based of parseInt in Java
1 11 13 is valid but 1 11 1a is invalid, so for all values we have a valid "string" iff all chars are 0-9 ignoring whitespace.
2: convert the ASCII value of a char to its integer value (eg. 48 => 0)
3: use a variable val to store an int such that for each char in a "substring" there is a corresponding integer digit. i.e. "1234" => 1234 append this to an int array and set val to 0 for reuse.
The following code demonstrates this algorithm:
int main() {
int i, c;
int size = 0;
int arr[10]; //max number of ints yours may differ
int val = 0;
int chars[1200]; //arbitrary size to fit largest "String"
int len = 0;
//Part 1: read in valid integer chars from stdin
while((c = getchar()) != EOF && (c < 58 && c > 47)) {
chars[len] = c;
len++;
}
//Part 2: Convert atoi manually. concat digits of multi digit integers and
// append to an int[]
for(i = 0; i < len; i++){
for(i = 0; i < len; i++){
if(chars[i] > 47 && chars[i] < 58){
while((chars[i] > 47 && chars[i] < 58)){
if(chars[i] == 48)
c = 0;
if(chars[i] == 49)
c = 1;
if(chars[i] == 50)
c = 2;
if(chars[i] == 51)
c = 3;
if(chars[i] == 52)
c = 4;
if(chars[i] == 53)
c = 5;
if(chars[i] == 54)
c = 6;
if(chars[i] == 55)
c = 7;
if(chars[i] ==56)
c = 8;
if(chars[i] == 57)
c = 9;
val = val*10 + c;
i++;
}
arr[size] = val;
size++;
if(size > 10) //we have a check to ensure size stays in bounds
return 1;
val = 0;
}
//Print: We'll make it a clean, organized "toString" representation
printf("[");
for(i = 0; i < size-1; i++){
printf("%d, ", arr[i]);
}
printf("%d]", arr[i];
return 0;
Again, this is the brute force method, but in cases like mine where you can't use the method concepts people use professionally or various C99 implements, this may be what you are looking for.

Resources