Trying to put some digits into a char array - c

I'm trying to create a char array made of some letters and numbers (the function was way more complex initially but i kept simplifying it to figure out why it doesn't work properly). So i have a char array in which i put 2 chars, and try to add some numbers to it.
For a reason i can't figure out, the numbers do not get added to the array. It might be really stupid but I'm new to C so here's the simplified code. Any help is much appreciated, thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char some_string[20];
char *make_str() {
some_string[0] = 'a';
some_string[1] = 'x';
int random = 0;
int rand_copy = 0;
random = (rand());
rand_copy = random;
int count = 2;
while ( rand_copy > 0 ) {
rand_copy = rand_copy / 10;
++count;
}
int i=2;
for (i=2; i<count; i++) {
some_string[i] = random%10;
random = random/10;
}
return (some_string);
}
int main(int argc, const char *argv[]) {
printf("the string is: %s\n",make_str());
return 0;
}

You have many problems:
resulting string is not zero-terminated. Add some_string[i] = '\0'; to fix this
character (char) is something like "a letter", but random % 10 produces a number (int) which when converted to character results in control code (ASCII characters 0-9 are control codes). You'd better use some_string[i] = (random % 10) + '0';
you're using fixed length string (20 characters), which may be enough, but it could lead to many problems. If you are a beginner and haven't learn dynamic memory allocation, than that's ok for now. But remember that fixed-length buffers are one of top-10 reasons for buggy C-code. And if you have to use fixed-length buffers (there are legitimate reason for doing this), ALLWAYS check if you are not overrunning the buffer. Use predefined constants for buffer length.
unless the whole point of your excercise is to try converting numbers to strings, use libc function like snprintf for printing anything into a string.
don't use global variable (some_string) and if you do (it's ok for a small example), there is no point in returning this value.
Slightly better version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_LENGTH 20
char some_string[BUF_LENGTH];
char *make_str() {
some_string[0] = 'a';
some_string[1] = 'x';
int random = rand();
int rand_copy = random;
int count = 2;
while (rand_copy > 0) {
rand_copy = rand_copy / 10;
++count;
}
int i;
for (i = 2; i < count; i++) {
/* check for buffer overflow. -1 is for terminating zero */
if (i >= BUF_LENGTH - 1) {
printf("error\n");
exit(EXIT_FAILURE);
}
some_string[i] = (random % 10) + '0';
random = random / 10;
}
/* zero-terminate the string */
some_string[i] = '\0';
return some_string;
}
int main(int argc, const char *argv[]) {
printf("the string is: %s\n",make_str());
return 0;
}

Related

C Program To Calculate Numbers Squared | Arguments Segmentation Fault

I'm a beginner to C, trying to write a program to calculate a square number. At my college we're not allowed to use printf() or scanf() which makes things a bit complicated.
This led me to using arguments to get input. I'm getting a segmentation fault (core dumped) when I try to compile. I think this comes from using argv and indexes but I'm not sure how to fix it.
Do you have some insight that might help? It would be much appreciated!
#include <unistd.h>
int main(int argc, char *argv[]) {
int number;
int square;
while(argc != 0) {
number = argv[1][square];
square = number * number;
write(1, &square, 1);
square++;
}
write(1, "\n", 1);
return 0;
}
The segmentation fault, if not caused by something else first will be caused here:
number = argv[1][square];//seg fault possible when square becomes
//larger than strlen(argv[1]) + 1
Attempting to access memory that the program process does not own, as above, will invoke undefined behavior.
Also, at the time this expression is executed:
square = number * number;
it is unknown what value was contained in square.
These two values should be initialized:
int number = 0;
int square = 0;//this specifically will cause problems later if not initialized
Also, at the time this is called:
number = argv[1][square];
argv[1] is a string, and needs to be converted to an integer before using.
number = atoi(argv[1]);
Next, the statement:
number = argv[1][square]; //seg fault possible as noted above.
will blow up when the value of square becomes larger than then string length of argv[1].
If your intent is squaring the value contained in argv[1] in its entirety as a single numeric value, it must first be converted from a string array, to an integer value, then you can easily get the square as you do in your code:
int number = atoi(argv[1]);
square = number * number;
If, as it appears in your code, you are interested in squaring each of the component integers making up the string, then given the input of "1234, to convert each of the digits inargv1from ASCII value to its numeric value. (i.e.val = argv1[x] - '0'==>x`), then square it, then move the the next character in the array and so on.... look at the other part of this answer below.
The following is an adaptation of your original to do this...
int main(int argc, char *argv[]) {
int number = 0;
int square = 0;
if(argc != 2)
{
printf("%s\n","Usage prog.exe <nnn>, where nnn is an integer value.\nProgram will exit.");
}
else
{
char *ptr = argv[1];
while(*ptr != '\0')
{
number = *ptr - '0';
square = number * number;
printf("%d\n", square);//write() not available on my system, replace as necessary
square++;
ptr++;
}
}
return 0;
}
So, for example given prog.exe "1234", the output is:
The completed code should look like this :
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
int number;
int square;
if(argc == 2) {
number = atoi(argv[1]);
square = number * number;
char sq_buffer[12];
sprintf(sq_buffer , "%d" , square);
strcat(sq_buffer , "\n");
write(1, (const void *) sq_buffer, strlen(sq_buffer));
}else{
char message[100];
strcpy(message , "Please specify exactly one argument \n");
write(1 , (const void *)message , strlen(message));
}
return 0;
}
When you say that you are not allowed to use 'printf', does that also include 'fprintf' and 'sprintf'? If so, then I would solve this problem like this:
void main( int argc, char **argv )
{
int i;
int j;
int square;
int value;
char buffer[256];
for (i = 1; i < argc; i++) {
/* Get the next integer from the args to the program */
value = atoi(argv[i]);
/* Calculate the square of that value */
square = value * value;
/* Now convert it to ASCII */
itoa(square, buffer, 10);
/* Write out the data */
write(1, buffer, strlen(buffer));
/* You could also use putchar() for it, like this: */
j = 0;
while (buffer[j] != '\0')
putchar(buffer[j++]);
}
}
If he doesn't want you using itoa(), then you could write your own int to ASCII conversion routine like this:
char *IntToASCII( int x )
{
static char buffer[256];
char *ptr;
int neg;
char *digits = "0123456789";
unsigned long tempX;
neg = (x < 0);
tempX = x;
if (neg) {
tempX *= -1;
}
ptr = buffer + sizeof(buffer) - 1;
*ptr = '\0';
do {
ptr--;
*ptr = digits[tempX % 10];
tempX /= 10;
} while (tempX > 0);
if (neg)
*ptr = '-';
return (ptr);
}
Or you can make 'buffer' an input parameter and remove the static declaration for it.
#define STDOUT_FILENO 1
#define MAX_INT_DIGITS (10+1) /*+1 for string null terminating*/
int main(int argc, char *argv[])
{
int number=0, square=0;
char ret_num[MAX_INT_DIGITS];
for (int i =1; i < argc; ++i)
{
number = atoi(argv[i])
square = number * number;
itoa(square, ret_num, 10);
write(STDOUT_FILENO, ret_num, strlen(ret_num));
/*write new line*/
write(STDOUT_FILENO, '\n', 1);
}
return 0;
}

Requiring help to understand arrays

I'm learning about arrays in C and I can't figure out why the following is not correct?
#include <cs50.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string plaintext = get_string();
int x = 5;
long long N = strlen(plaintext);
string a = plaintext;
long long c = 0;
int z = x;
for(int i = 0; i < N + (N/x) ; i++)
{
if( i == x)
{
a[c] = 32;
c++;
z = (z + x);
//printf("%c\n", a[c]);
}
a[c] = plaintext[i];
//printf("%c\n", a[c]);
c++;
}
printf("%s\n", a);
}
It's meant to insert spaces into a string of text after every x chars... I know it's not efficient (I reckon I need something called pointers) but why isn't it working? I went through it using a debugger and it seems like my original string is changing as I go... but why?
Assuming string is char * then text and a point to the same string. That explains why your original string changes. What you can do is:
string a= malloc(N+1 + N/x +1);
This allocates space for a new string, into which you copy the original with a space after every x characters. Add 1 for the terminating null character and 1 "to be safe" when x or N are odd.
#include <bits/stdc++.h>
using namespace std;
#define freinput "input.txt","r",stdin
#define freoutput "output.txt","w",stdout
#define mp make_pair
#define fi first
#define sc second
#define ellapse printf("Time : %0.3lf\n",clock()*1.0/CLOCKS_PER_SEC);
typedef long long ll;
typedef unsigned long int uld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
string s;
string stringInsertion(int x,string neww){
for(int i = 0;i<s.size();i++){
if(i!=0 && i%x==0){
neww=neww+' '+s[i];
}
else neww+=s[i];
}
return neww;
}
int main(){
cin>>s;
int x = 2;
string neww="";
cout<<stringInsertion(x,neww);
}
just set the x number.hope this help
Okay, let's do something similar first: Print out the string with spaces. Use i to loop through the string. Every time i is evenly divisibly by x, we print a space before we print the character, but not at the beginning:
void print_spaced(const char *s, int x)
{
int i;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) putchar(' ');
putchar(s[i]);
}
putchar('\n');
}
You don't need to determine the length beforehand, because you can stop when you hit the terminating null character. That is, keep going as long as s[i] is not null. (Recall that s[i] is the same as s[i] != '\0' and similarly, i is the same as i != 0.)
Now let's fill a char array with the spaced out string instead of printing it:
int space_out_unsafe(char *res, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) res[k++] = ' ';
res[k++] = s[i];
}
res[k] = '\0';
return k;
}
This function takes an additional parameter: A char buffer to fill. It has a second index, k, which is the current length of the result buffer. Whenever we printed in the first version, we now append a character to the string:
res[k++] = '#';
Tis overwrites the current end and moves k on one position. We don't write a newline at the end, but we must null-terminate the result.
There is one problem, though: The buffer may overflow; note how I have labelled the function above unsafe. Arrays in C have a fixed size and won't grow automatically when something is appended. It is there fore a good idea to pass the maximum buffer size max to the function and check for overflow before appending:
int space_out(char *res, int max, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0 && k < max - 1) res[k++] = ' ';
if (k < max - 1) res[k++] = s[i];
}
res[k] = '\0';
return k;
}
You can now use this function like this:
char res[20];
space_out(res, sizeof(res), "Doremifasola", 2);
puts(res);
There are other ways to accomplish this. You could allocate the memory dynamically, as Paul suggested. That way, you can cater for the additional space you need, but you also make the caller of the function take care of cleaning up the allocated memory with free. Dynamically allocating memory is something to look into after your first week. :)
Another possibility is to space out the string in place, that modify the contents of the original buffer. You still have to take care to provide the extra space, though. (Usually, in-place midofication is used when the result string is shorter, e.g. when filtering out characters.) You should also process your string from the and as not to overwrite data you need later with spaces. If you feel confident, that's an exercise for next week, too.

Reverse a character array without changing value of number?

I have for example a string (mathematical equation in postfix notation) that looks like this: The numbers are 5.33,5.32,6.33,3.22
5.335.32*6.333.22++
I'm looking to make it into prefix notation but simply reversing the string won't work due to the fact it has to retain the value of the number.
I've thought of doing a normal character by character swap in a for loop, and when encountering a digit make that into a substring and place it on afterwards but I haven't gotten it to work properly and now I'm stuck.
My end-goal is to make a binary expression tree out of that, so if there's an easier way than doing this also please let me know.
A stack-based approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *postfix_to_prefix(const char *string) {
char operator, *stack[1024];
int s = 0, number, fraction;
const char *tokens = string;
while (1) {
if (sscanf(tokens, "%1d.%2d", &number, &fraction) == 2) {
stack[s] = malloc(sizeof("1.00"));
(void) sprintf(stack[s++], "%4.2f", number + (fraction / 100.0));
tokens += strlen("1.00");
} else if (sscanf(tokens, "%c", &operator) == 1) {
char *operand1 = stack[--s];
char *operand2 = stack[--s];
stack[s] = malloc(strlen(operand1) + strlen(operand1) + sizeof(operator) + sizeof('\0'));
(void) sprintf(stack[s++], "%c%s%s", operator, operand1, operand2);
free(operand1);
free(operand2);
tokens += sizeof(operator);
} else {
break;
}
}
return stack[--s];
}
int main() {
const char *string = "5.335.32*6.333.22++";
printf("%s\n", string);
char *inverted = postfix_to_prefix(string);
printf("%s\n", inverted);
free(inverted);
return 0;
}
OUTPUT
> ./a.out
5.335.32*6.333.22++
++3.226.33*5.325.33
>
This is a bare bones implementation with no real error checking nor other finishing touches. You'll want to check that non-communitive operations like subtraction and division come out with the operands in the correct order and reverse them if not.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char exp[] = "5.335.32*6.333.22++";
size_t len = strlen(exp);
char temp[len];
char *p = temp;
for(int i = len-1; i >= 0; ){
if(isdigit(exp[i])){
memcpy(p, &exp[i-4+1], 4);//all number have a length of 4
p += 4;
i -= 4;
} else {
*p++ = exp[i--];//length of op is 1
}
}
memcpy(exp, temp, len);//Write back
puts(exp);//++3.226.33*5.325.33
return 0;
}

Get to number from an array and assign to one int

I'm working on my homework and trying to get two characters which are numbers from an array for example ABC10DEF
I want to get 10 and store it in an int type.
number_holder_1 = back[3] - '0';
number_holder_2 = back[4] - '0';
number = number_holder_1 * 10 + number_holder_2;
This doesn't work I don't know why.
When I print out the value of number_holder_1 it does display 1 and when I display number_holder_2 it display 0 but when I print number it just display 0
I don't know how.
UPDATE:
The number, number_holder_1 and number_holder_2 are define as int type.
the array called back that holding ABC10DEF is passing from the main.
It appears to be an implementation mistake, because using what you have given, with some better variable names, it does work.
#include <stdio.h>
#include <ctype.h>
int letter2int(char c) {
int n;
if (isdigit(c)) {
n = c - '0';
} else {
n = -1; /* error */
}
/* for debugging */
printf("For character '%c' we get number '%d'.\n", c, n);
return n;
}
int main(int argc, char** argv) {
const char str[] = "ABC10DEF";
int tens, ones;
int result;
tens = letter2int(str[3]);
ones = letter2int(str[4]);
result = tens * 10 + ones;
printf("Result: %d\n", result);
return 0;
}
This can be generalized to either form a atoi function (ASCII to integer) or extract the first number that occurs in a string (terminated by any non-digit character) by using a loop and a char pointer to index over the string str.
Using i as the zero-based index, result += number * (int)pow(10, i);.

Grab all integers from irregular strings in C

I am looking for a (relatively) simple way to parse a random string and extract all of the integers from it and put them into an Array - this differs from some of the other questions which are similar because my strings have no standard format.
Example:
pt112parah salin10n m5:isstupid::42$%&%^*%7first3
I would need to eventually get an array with these contents:
112 10 5 42 7 3
And I would like a method more efficient then going character by character through a string.
Thanks for your help
A quick solution. I'm assuming that there are no numbers that exceed the range of long, and that there are no minus signs to worry about. If those are problems, then you need to do a lot more work analyzing the results of strtol() and you need to detect '-' followed by a digit.
The code does loop over all characters; I don't think you can avoid that. But it does use strtol() to process each sequence of digits (once the first digit is found), and resumes where strtol() left off (and strtol() is kind enough to tell us exactly where it stopped its conversion).
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
const char data[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
long results[100];
int nresult = 0;
const char *s = data;
char c;
while ((c = *s++) != '\0')
{
if (isdigit(c))
{
char *end;
results[nresult++] = strtol(s-1, &end, 10);
s = end;
}
}
for (int i = 0; i < nresult; i++)
printf("%d: %ld\n", i, results[i]);
return 0;
}
Output:
0: 112
1: 10
2: 5
3: 42
4: 7
5: 3
More efficient than going through character by character?
Not possible, because you must look at every character to know that it is not an integer.
Now, given that you have to go though the string character by character, I would recommend simply casting each character as an int and checking that:
//string tmp = ""; declared outside of loop.
//pseudocode for inner loop:
int intVal = (int)c;
if(intVal >=48 && intVal <= 57){ //0-9 are 48-57 when char casted to int.
tmp += c;
}
else if(tmp.length > 0){
array[?] = (int)tmp; // ? is where to add the int to the array.
tmp = "";
}
array will contain your solution.
Just because I've been writing Python all day and I want a break. Declaring an array will be tricky. Either you have to run it twice to work out how many numbers you have (and then allocate the array) or just use the numbers one by one as in this example.
NB the ASCII characters for '0' to '9' are 48 to 57 (i.e. consecutive).
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
int length = strlen(input);
int value = 0;
int i;
bool gotnumber = false;
for (i = 0; i < length; i++)
{
if (input[i] >= '0' && input[i] <= '9')
{
gotnumber = true;
value = value * 10; // shift up a column
value += input[i] - '0'; // casting the char to an int
}
else if (gotnumber) // we hit this the first time we encounter a non-number after we've had numbers
{
printf("Value: %d \n", value);
value = 0;
gotnumber = false;
}
}
return 0;
}
EDIT: the previous verison didn't deal with 0
Another solution is to use the strtok function
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," abcdefghijklmnopqrstuvwxyz:$%&^*");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " abcdefghijklmnopqrstuvwxyz:$%&^*");
}
return 0;
}
Gives:
112
10
5
42
7
3
Perhaps not the best solution for this task, since you need to specify all characters that will be treated as a token. But it is an alternative to the other solutions.
And if you don't mind using C++ instead of C (usually there isn't a good reason why not), then you can reduce your solution to just two lines of code (using AXE parser generator):
vector<int> numbers;
auto number_rule = *(*(axe::r_any() - axe::r_num())
& *axe::r_num() >> axe::e_push_back(numbers));
now test it:
std::string str = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got your numbers back.
And as a bonus, you don't need to change anything when parsing unicode wide strings:
std::wstring str = L"pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got the same numbers back.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(void)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
char *pos = input;
int integers[strlen(input) / 2]; // The maximum possible number of integers is half the length of the string, due to the smallest number of digits possible per integer being 1 and the smallest number of characters between two different integers also being 1
unsigned int numInts= 0;
while ((pos = strpbrk(pos, "0123456789")) != NULL) // strpbrk() prototype in string.h
{
sscanf(pos, "%u", &(integers[numInts]));
if (integers[numInts] == 0)
pos++;
else
pos += (int) log10(integers[numInts]) + 1; // requires math.h
numInts++;
}
for (int i = 0; i < numInts; i++)
printf("%d ", integers[i]);
return 0;
}
Finding the integers is accomplished via repeated calls to strpbrk() on the offset pointer, with the pointer being offset again by an amount equaling the number of digits in the integer, calculated by finding the base-10 logarithm of the integer and adding 1 (with a special case for when the integer is 0). No need to use abs() on the integer when calculating the logarithm, as you stated the integers will be non-negative. If you wanted to be more space-efficient, you could use unsigned char integers[] rather than int integers[], as you stated the integers will all be <256, but that isn't a necessity.

Resources