String of variable length to int array? - c

I have a string which is in the form
"1 2 8 4 9 0 " etc. I know it will follow the format of integer, space, integer...
However, I can't guarentee the length. I know the maximum length, if that helps.
I thought to use sscanf, but it needs a finite number of integers.
Any ideas how I can turn "1 2 3 " into an array where
A[0] = 1
A[1] = 2
A[2] = 3
Thanks!

strtol indicates where in the string it failed.
For a string like "1 2 3 ..." it will read the 1 and fail right afterwards; if you then pass that failure point (" 2 3 ...") to strtol it will read 2 and fail right afterwards, ..., ...
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char input[] = "6 82 -7453 4 0 63 ";
char *err = " ", *curr = input;
int x, k = 0;
while (*curr && isspace((unsigned char)*err)) {
x = strtol(curr, &err, 10);
printf("#%d: %d\n", k++, x);
curr = err + !!*err; // do not advance past the '\0'
}
return 0;
}
See it in action -- unlike the snippet above, the one at ideone initializes k with 1 :/ and doesn't deal well with inputs that end in whitespace.

Use
rc = sscanf(string, "%d%n", &array[i], &len);
In a loop. Test the rc, and use len to skip to the next item.

It's really not that complicated:
Calculate the length of the string with strlen
Allocate enough memory for the array with malloc
Iterate over the string again and populate the array
See it in action.

One of the many ways could be to use strtok to tokenize the string with the separator as space & the return value of each strtok call can be used with sscanf for single integer. As you know the maximum length you can iterate the array to be used with sscanf something on these lines.
Hope this helps!

Related

C character array comparison

Ok so I was doing a coding challenge on codewars.com and the challenge was to take a string as input and return a string where in place of the letters are instead the number of the alphabet that matches the letter.
Everything except letters are to be ignored.
ex: "aab" would return "1 1 2"
There should be a space between each number that represents a letter in the alphabet.
So, when I run this code on my IDE (which is xcode using c99) Everything looks good and the strcmp() function says the 2 strings are equal.
The website I'm on uses C11 I believe but I don't see that causing the error.
When I run this code on the challenge website it passes a couple of tests but then fails a couple also. It fails when the input string is "", and it also fails on the string that I have used in the code below, but again it does not fail when I run it on my ide.
My questions are:
1) Any idea what is causing this bug?
2) What would you have done differently as far as the code is concerned
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *alphabet_position(char *text)
{
int i,letter_position;
unsigned long int size = strlen(text);
char *result = malloc(sizeof(int)*size + 1);
char int_string[10];
char temp = ' ';
//If String wasn't blank
if (strcmp(text, "")!=0)
{
for (i=0; i<size-1; i++)
{
//If it is a letter
if (isalpha(text[i]))
{
temp = tolower(text[i]);
if (temp == 'a')
strcat(result, "1");
else
{
letter_position = temp - 'a' + 1;
sprintf(int_string,"%d",letter_position);
strcat(result, int_string);
}
//Print space after letter until the last letter
if (i!=size-2)
strcat(result, " ");
}
}
strcat(result, "\0");
return result;
}
else
{
strcat(result, "\0");
return result;
}
}
int main(void)
{
char *string = alphabet_position("The narwhal bacons at midnight.");
char *expected_output = "20 8 5 14 1 18 23 8 1 12 2 1 3 15 14 19 1 20 13 9 4 14 9 7 8 20";
printf("Your output %s\n", alphabet_position("The narwhal bacons at midnight."));
printf("Expt output %s\n", "20 8 5 14 1 18 23 8 1 12 2 1 3 15 14 19 1 20 13 9 4 14 9 7 8 20");
printf("\n");
printf("your len %lu\n", strlen(alphabet_position("The narwhal bacons at midnight.")));
printf("Expt len %lu\n", strlen(expected_output));
if (strcmp(string, expected_output)==0)
printf("Equal\n");
else
printf("Not equal\n");
return 0;
}
You have two serious problems.
First, you're not initializing the contents of the result array to an empty string. After you call malloc(), add:
result[0] = '\0';
malloc() doesn't initialize the memory it allocates. There's another function calloc() that takes slightly different arguments and initializes the memory to zeroes. But you only need the first character to be zero, so there's no need for that.
Second, the for loop is not processing the last character of text. It should be:
for (i = 0; i < size; i++)
Similarly, the test for whether to add a space should be if (i != size-1). Did you think strlen() counts the null character at the end?
The amount of space you specify in malloc() is not correct, but in practice it won't cause a problem. sizeof(int) has nothing to do with the number of characters it takes to show the value of an integer. Since you're just printing the alphabetical position, it will be at most 26, so you need 3 characters for every input character. Therefore, it should be:
char *result = malloc(3 * size + 1);
Your allocation works because sizeof(int) is generally at least 4, so you're allocating more than enough space.
There are other minor problems that don't affect the correctness of the result:
You don't need the if statement that treats 'a' specially, the code you have in else will work for all letters.
You don't need strcat(result, "\0") at the end. result has to already be null-terminated in order for you to use it as an argument to strcat(), so there's no point in using strcat() to add a null terminator.

How to split string (character) and variable in 1 line on C?

How can I split character and variable in 1 line?
Example
INPUT
car1900food2900ram800
OUTPUT
car 1900
food 2900
ram 800
Code
char namax[25];
int hargax;
scanf ("%s%s",&namax,&hargax);
printf ("%s %s",namax,hargax);
If I use code like that, I need double enter or space for make output. How can I split without that?
You should be able to use code like this to read one name and number:
if (scanf("%24[a-zA-Z]%d", namax, &hargax) == 2)
…got name and number OK…
else
…some sort of problem to be reported and handled…
You would need to wrap that in a loop of some sort in order to get three pairs of values. Note that using &namax as an argument to scanf() is technically wrong. The %s, %c and %[…] (scan set) notations all expect a char * argument, but you are passing a char (*)[25] which is quite different. A fortuitous coincidence means you usually get away with the abuse, but it is still not correct and omitting the & is easy (and correct).
You can find details about scan sets etc in the POSIX specification of scanf().
You should consider reading a whole line of input with fgets() or POSIX
getline(), and then processing the resulting string with sscanf(). This makes error reporting and error recovery easier. See also How to use sscanf() in loops.
Since you are asking this question which is actually easy, I presume you are somewhat a beginner in C programming. So instead of trying to split the input itself during the input which seems to be a bit too complicated for someone who's new to C programming, I would suggest something simpler(not efficient when you take memory into account).
Just accept the entire input as a String. Then check the string internally to check for digits and alphabets. I have used ASCII values of them to check. If you find an alphabet followed by a digit, print out the part of string from the last such occurrence till the current point. And while printing this do the same with just a slight tweak with the extracted sub-part, i.e, instead of checking for number followed by letter, check for letter followed by digit, and at that point print as many number of spaces as needed.
just so that you know:
ASCII value of digits (0-9) => 48 to 57
ASCII value of uppercase alphabet (A-Z) => 65 to 90
ASCII value of lowercase alphabets (a-z)
=> 97 to 122
Here is the code:
#include<stdio.h>
#include<string.h>
int main() {
char s[100];
int i, len, j, k = 0, x;
printf("\nenter the string:");
scanf("%s",s);
len = strlen(s);
for(i = 0; i < len; i++){
if(((int)s[i]>=48)&&((int)s[i]<=57)) {
if((((int)s[i+1]>=65)&&((int)s[i+1]<=90))||(((int)s[i+1]>=97)&&((int)s[i+1]<=122))||(i==len-1)) {
for(j = k; j < i+1; j++) {
if(((int)s[j]>=48)&&((int)s[j]<=57)) {
if((((int)s[j-1]>=65)&&((int)s[j-1]<=90))||(((int)s[j-1]>=97)&&((int)s[j-1]<=122))) {
printf("\t");
}
}
printf("%c",s[j]);
}
printf("\n");
k = i + 1;
}
}
}
return(0);
}
the output:
enter the string: car1900food2900ram800
car 1900
food 2900
ram 800
In addition to using a character class to include the characters to read as a string, you can also use the character class to exclude digits which would allow you to scan forward in the string until the next digit is found, taking all characters as your name and then reading the digits as an integer. You can then determine the number of characters consumed so far using the "%n" format specifier and use the resulting number of characters to offset your next read within the line, e.g.
char namax[MAXNM],
*p = buf;
int hargax,
off = 0;
while (sscanf (p, "%24[^0-9]%d%n", namax, &hargax, &off) == 2) {
printf ("%-24s %d\n", namax, hargax);
p += off;
}
Note how the sscanf format string will read up to 24 character that are not digits as namax and then the integer that follows as hargax storing the number of characters consumed in off which is then applied to the pointer p to advance within the buffer in preparation for your next parse with sscanf.
Putting it altogether in a short example, you could do:
#include <stdio.h>
#define MAXNM 25
#define MAXC 1024
int main (void) {
char buf[MAXC] = "";
while (fgets (buf, MAXC, stdin)) {
char namax[MAXNM],
*p = buf;
int hargax,
off = 0;
while (sscanf (p, "%24[^0-9]%d%n", namax, &hargax, &off) == 2) {
printf ("%-24s %d\n", namax, hargax);
p += off;
}
}
}
Example Use/Output
$ echo "car1900food2900ram800" | ./bin/fgetssscanf
car 1900
food 2900
ram 800

Putting users input consisting of numbers separated by commas into an array?

I am taking in 10 numbers from the user (user enters them at a prompt, and the numbers are separated by commas, as so: 245645, -243, 4245). How can I put these elements into an array? As shown below, I have used scanf which does not work as I had hoped. Any suggestions would be appreciated.
//User will pass ten numbers, separated by commas. This is to be put into an array.
#include <stdio.h>
int main ()
{
int A[10]; // array to contain in users input.
printf("Enter your numbers: ");
scanf("%d", &A[10]);
return 0;
}
You have to consume the comma as well in scanf:
for(int i=0; i<10; i++) { /* for each element in A */
if(0==scanf("%d,", &A[i])) { /* read a number from stdin into A[i] and then consume a commma (if any) */
break; /* if no digit was read, user entered less than 10 numbers separated by commas */
/* alternatively error handling if fewer than 10 is illegal */
}
}
I won't write the whole thing for you.
But I can definitely help.
One of the ways to do that will be:
Get a string that contains 10 comma-separated numbers: fgets() may be?
Validate the string, trim white-spaces as well, makes life easier
Pick out a number from string: strtol() may be?
Search for a ',' character in the string, and set pointer to the next index after ',': strchr() may be?
Repeat steps 3 and 4 for a total of 10 times (from here, 9 times actually)
Print the numbers
The code below would do half of your job. The only remaining part would be to get string from user and validate it.
The intention to have a string declared and initialised upfront is to put more emphasise on actual parsing of data which appear complicated to beginners (no offence).
Before we look at the code below, lets read a few things first.
You might want to take a look at the man page for strtol() function
You might want to take a look at the man page for fgets() function, which is not used in the code below, but you may end-up using it to achieve step 1.
I already concede the fact that this may not be the best way to achieve it, and I would happily agree that this code below can be made better in thousand ways by adding various error check, but I leave that to you to explore and implement.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
int i = 0, j = 0;
char *Str = "1,11,21,1211,111221,312211,1234,4321,123,789";
char *ptr;
long ret;
long array[10] = { [0 ... 9] = 0 };
// So, lets assume step 1 and 2 are taken care of.
// Iterate though the data for 10 times
for(i = 0; i < 10; i++)
{
ret = strtol(Str, &ptr, 10);
// Check if its a number
if(ret != 0)
{
// Its is a number!
// Put it in the array
array[j] = ret;
// Increment the index so that next number will not over-write the existing one
j++;
// Find the next ',' in the string
Str = strchr(Str, ',');
if(Str == NULL)
{
// Handle this condition that there are no more commas in the string!
break;
}
// Assuming that the ',' is found, increment the pointer to index next to ','
Str++;
}
}
// Print the array
for(i = 0; i < j; i++)
printf("%ld\n", array[i]);
}
This prints the following output:
1
11
21
1211
111221
312211
1234
4321
123
789
Hope I have got you started, Good luck.

simple string counter program debugging (pointers)

I am new to C programming and pointers.
I made a simple program where I can read in the string and the program tells you how many characters are there and how many alphabets had appeared how many times.
Somehow, my output is not right. I think it might be my pointer and dereferencing problem.
here is my main:
extern int* count (char* str);
int main(int argc, char* argv[])
{
int numOfChars =0;
int numOfUniqueChars = 0;
char str[80];
int *counts;
strcpy(str, argv[1]);
printf("counting number of characters for \"%s\"..\n", str);
printf("\n");
counts = count(str);
int j;
for (j =0; j<sizeof(counts); j++)
{
if(counts[j])
printf("character %c", *str);
printf("appeared %d times\n", counts[j]);
numOfChars++;
numOfUniqueChars++;
}
printf("\"%s\" has a total of %d character(s)\n", str, numOfChars);
printf(wow %d different ascii character(s) much unique so skill\n", numOfUniqueChars);
}
and this is my count function:
int* count(char* str)
{
int* asctb = malloc(256);
int numOfChars =0;
int i;
int c;
for(i = 0; i<strlen(str); i++)
c = str[i];
asctb[c]++;
numOfChars += strlen(str);
return asctb;
}
and when I compile and run it, my result comes up like this:
./countingCharacter doge
counting number of characters for "doge"...
appeared 0 times
appeared 0 times
appeared 0 times
appeared 0 times
"doge" has a total of 4 character(s)
wow 4 different ascii character(s) much unique so skill
But, I want my result to be like this:
Character d appeared 1 times
Character e appeared 1 times
Character g appeared 1 times
Character o appeared 1 times
"doge" has a total of 4 character(s)
wow 4 different ascii character(s) much unique so skill
Any help will be much appreciated.
Thanks in advance!
EDIT:
i added curly braces for my for loop in the main function.
now i get this result:
./countingCharacter doge
character # appeared 7912 times
character d appeared 1 times
character e appeared 1 times
character g appeared 1 times
character o appeared 1 times
why do I get that "#" in the beginning??
As #kaylum said, one particularly large issue is your use of braces. If you don't use braces with a control flow statement (if, for, while, etc.), only the next line is counted as a part of that statement. As such, this segment:
if (counts[j])
printf("character %c", *str);
printf("appeared %d times\n", counts[j]);
/* ... */
...will only execute the first printf if counts[j] != 0, but will unconditionally execute the following statements.
Your use of malloc is also incorrect. malloc(256) will only allocate 256 bytes; one int is generally 4 bytes, but this differs based on the compiler and the machine. As such, when malloc'ing an array of any type, it's good practice to use the following technique:
type *array = malloc(element_count * sizeof(type));
In your case, this would be:
int *asctb = malloc(256 * sizeof(int));
This ensures you have room to count all the possible values of char. In addition, you'll have to change the way you iterate through counts as sizeof (counts) does not accurately represent the size of the array (it will most likely be 4 or 8 depending on your system).
The variable numOfChars will not behave the way you expect it to. It looks to me like you're trying to share it between the two functions, but because of the way it's declared this will not happen. In order to give global access to the variable, it needs to be declared at global scope, outside of any function.
Also, the line:
printf("character %c ", *str);
...neither keeps track of what characters you've printed nor which you're supposed to, instead just repeatedly printing the first character. *str should be (char)j, since you're printing ASCII values.
That ought to do it, I think.
If you are new to C, there are a number of issues in your code you need to pay attention to. First, if a function returns a value, validate that value. Otherwise, from that point in your code on, you can have no confidence that it is actually operating on the value or memory location you think it is. For example, each of the following should be validated (or changed to stay within allowable array bounds):
strcpy(str, argv[1]);
int* asctb = malloc(256);
counts = count(str);
What if argv[1] had 100 chars? What if malloc returned NULL? How do you know count succeeded? Always include the necessary validations needed by your code.
While not an error, the standard coding style for C avoids caMelCase variables in favor of all lower-case. See e.g. NASA - C Style Guide, 1994 So
int numOfChars =0;
int numOfUniqueChars = 0;
could simply be nchars and nunique.
Next, all your if and for loop syntax fails to encapsulate the required statements in braces, e.g. {...} to create a proper block for your if or for. For example, the following:
for(i = 0; i<strlen(str); i++)
c = str[i];
asctb[c]++;
only loops over c = str[i]; and asctb[c]++; is only executed AFTER the loop exits.
You must initialize your variable, (especially your array elements) before you attempt to reference them otherwise undefined behavior results. (it could seem to work, give weird output like a strange "#" character, or segfault, that's why it is undefined). You have a big problem here:
int* asctb = malloc(256);
None of the values in asctb are initialized. So when you return the array to main() and loop over all values in the array, every element that was not explicitly assigned a value causes undefined behavior. You can either set all values to 0 with memset, or recognize when you need all values initialized and use calloc instead:
int *asctb = calloc (1, 256);
Avoid the use of "magic-numbers" in your code. 256 above is a great example. Don't litter you code with these magic-numbers, instead defined a constant for them at the beginning of your code with either #define or for numerical constants, use an enum instead.
Lastly, in any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed using free when it is no longer needed. You should validate your memory use by running your code though a Memory Error Checking Program, such as valgrind on Linux. It's simple to do and will save you from yourself more times than you can imagine.
Putting all these pieces together and fixing additional logic errors in your code, you look like you were attempting something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* constants for max characters in str and values in asctb */
enum { MAXC = 80, MAXTB = 128 };
int *count (char *str);
int main (int argc, char **argv) {
if (argc < 2) { /* validate str given as argument 1 */
fprintf (stderr, "error: insufficient input, usage: %s str.\n",
argv[0]);
return 1;
}
/* initialize all variables avoid CamelCase names in C */
char str[MAXC] = "";
int j = 0, nchars = 0, nunique = 0;
int *counts = NULL;
strncpy (str, argv[1], MAXC - 1); /* limit copy len */
str[MAXC - 1] = 0; /* nul-terminate str */
printf ("\ncounting number of characters for \"%s\"..\n\n", str);
if (!(counts = count (str))) { /* validate return */
fprintf (stderr, "error: count() returned NULL.\n");
return 1;
}
for (j = 0; j < MAXTB; j++)
if (counts[j]) {
printf ("character '%c' appeared: %d times\n",
(char)j, counts[j]);
nchars += counts[j];
nunique++;
}
free (counts); /* free allocated memory */
printf ("\n\"%s\" has a total of %d character(s)\n", str, nchars);
printf (" wow %d different ascii character(s) much unique so skill\n\n",
nunique);
return 0; /* main is a function of type 'int' and returns a value */
}
int *count (char *str)
{
if (!str) return NULL; /* validate str */
int *asctb = calloc (1, sizeof *asctb * MAXTB);
size_t i; /* you are comparing with size_t in loop */
if (!asctb) { /* validate memory allocation - always */
fprintf (stderr, "count() error: virtual memory exhausted.\n");
return NULL;
}
for(i = 0; i < strlen(str); i++)
asctb[(int)str[i]]++; /* array indexes are type 'int' */
return asctb;
}
(note: the first 30 characters in counts are in the non-printable range, see ASCIItable.com. The indexes were left as you had them, but note, in practice you may want to shift them unless you are interested in counting the non-printable \t, \n, etc. chars).
Example Use/Output
$ ./bin/ccount "address 12234"
counting number of characters for "address 12234"..
character ' ' appeared: 1 times
character '1' appeared: 1 times
character '2' appeared: 2 times
character '3' appeared: 1 times
character '4' appeared: 1 times
character 'a' appeared: 1 times
character 'd' appeared: 2 times
character 'e' appeared: 1 times
character 'r' appeared: 1 times
character 's' appeared: 2 times
"address 12234" has a total of 13 character(s)
wow 10 different ascii character(s) much unique so skill
Look over the logic and syntax corrections and let me know if you have any further questions.

Postfix evaluation in C

I’m taking a course in C and we have to make a program for the classic Postfix evaluation problem. Now, I’ve already completed this problem in java, so I know that we have to use a stack to push the numbers into, then pop them when we get an operator, I think I’m fine with all of that stuff. The problem I have been having is scanning the postfix expression in C. In java it was easier because you could use charAt and you could use the parseInt command. However, I’m not aware of any similar commands in C. So could anyone explain a method to read each value from a string in the form:
4 9 * 0 - =
Where the equals is the signal of the end of the input.
Any help would be greatly appreciated and thank you in advance :)
Let's suppose you input is in an array of characters.
char input[] = "4 9 * 0 - =";
you can access individual characters by accessing each individual array element
if (input[4] == '*') /* deal with star */;
or you can use pointer arithmetic and parse from a different point in the input (remember to #include <stdio.h> for the prototype for `sscanf´)
if (sscanf(input + 2, "%d", &number) != 1) /* deal with error */;
Or, as suggested by Chris Lutz in a comment, use strtol (after the proper #include <stdlib.h>)
number = strtol(input + 2, &next, 10);
/* don't forget to check for errors! */
/* `next` now points to the character after the `long` at position 2 in the array */
C strings are arrays of chars: char[] or char*.
you can use a for loop to iterate it and get each characher by it's index:
for (int i = 0; i < strlen(yourString); i++)
{
char ch = yourString[i];
// ...
}
Also there is a function, strtok() that might be helpful here for tokenizing the string:
#include <string.h>
#define NULL (void*)0
char yourString[] = "4 9 * 0 - =";
char delimiters[] = " "; // could be " +*/-=" depending on your implementation
char *token = NULL;
token = strtok(yourString, delimiters);
while(token != NULL)
{
printf("current token is: %s\n", token);
// do what ever you want with the token
token = strtok(NULL, delimiters); // next token
}
You can also know with sscanf how many items have been read (the counter of well read data items is the result of sscanf) and what is the relative position (using the %n format specifier).
so you could also code
int pos = 0;
int endpos = 0;
int val = 0;
if (sscanf(input + pos, "%d %n", &val, &endpos) >= 1) {
// val has been read as an integer, handle it
stack[top++] = val;
pos += endpos; // skip to next token in input
}
There are many more ways of doing that. You might want to read about lexers and parsers, e.g. with flex and bison, or antlr, etc.

Resources