If I want to write in for loop (for example) something with the next mention:
for(int i=0;i<5;i++) {
char* str_3="atom_3";
if(strcmp(str_3,"atom_i")!=0){ // I know that it's not true to get it by
//this line.
printf("FALSE");
}
}
I want to get effect so that str_i will be compared with atom_0, atom_1 , ... , atom_4.
How can I do it?
How can I write a string that changes from iteration to iteration?
... to get effect so that str_i will be compared with "atom_0", "atom_1" , ... , "atom_4".
Construct the compare string on each iteration.
// This is not elegant, yet meets OP goals.
for(int i=0;i<5;i++) {
char atom_i[30];
sprintf(atom_i, "atom_%d", i);
if(strcmp(str_i, atom_i)!=0){
printf("FALSE");
}
}
Yet a better approach would scan str_i and avoid iteration.
int d = 0;
char ch; // Use to look for extra text
if (sscanf(str_i, "atom_%d%c", &d, &ch) == 1) {
if (d >= 0 && d < 5) {
; // do something with str_i
}
}
Related
I came up with the following basic item to reverse a string in C:
void reverse(char in[], char out[]) {
int string_length = 0;
for(int i=0; in[i] != '\0'; i++) {
string_length += 1;
}
for(int i=0; i < string_length ; i++) {
out[string_length-i] = in[i];
}
out[string_length+1] = '\0';
}
Is there a way to do this in one for loop or is it necessary to first use a for length to get the string length, and then do a second one to reverse it? Are there other approaches to doing a reverse, or is this the basic one?
Assuming you can't use functions to get the string length and you want to preserve the second loop I'm afraid this is the shortest way.
Just as a side-note though: this code is not very safe as at for(int i=0; in[i] != '\0'; i++) you are not considering cases where the argument passed to parameter in is not a valid C string where there isn't a single \0 in all elements of the array pointed by in and this code will end up manifesting a buffer over-read at the first for loop when it will read beyond in boundaries and a buffer overflow in the second for loop where you can write beyond the boundaries of out. In functions like this you should ask the caller for the length of both arrays in and out and use that as a max index when accessing them both.
As pointed by Rishikesh Raje in comments: you should also change the exit condition in the second for loop from i <= string_length to i < string_length as it will generate another buffer over-read when i == string_length as it will access out by a negative index.
void reverse(char *in, char *out) {
static int index;
index = 0;
if (in == NULL || in[0] == '\0')
{
out[0] = '\0';
return;
}
else
{
reverse(in + 1, out);
out[index + 1] = '\0';
out[index++] = in[0];
}
}
With no loops.
This code is surely not efficient and robust and also won't work for multithreaded programs. Also the OP just asked for an alternative method and the stress was on methods with lesser loops.
Are there other approaches to doing a reverse, or is this the basic one
Also, there was no real need of using static int. This would cause it not to work with multithreaded programs. To get it working correct in those cases:
int reverse(char *in, char *out) {
int index;
if (in == NULL || in[0] == '\0')
{
out[0] = '\0';
return 0;
}
else
{
index = reverse(in + 1, out);
out[index + 1] = '\0';
out[index++] = in[0];
return index;
}
}
You can always tweak two loops into one, more confusing version, by using some kind of condition to determine which phase in the algorithm you are in. Below code is untested, so most likely contains bugs, but you should get the idea...
void reverse(const char *in, char *out) {
if (*in == '\0') {
// handle special case
*out = *in;
return;
}
char *out_begin = out;
char *out_end;
do {
if (out == out_begin) {
// we are still looking for where to start copying from
if (*in != '\0') {
// end of input not reached, just go forward
++in;
++out_end;
continue;
}
// else reached end of input, put terminating NUL to out
*out_end = '\0';
}
// if below line seems confusing, write it out as 3 separate statements.
*(out++) = *(--in);
} while (out != out_end); // end loop when out reaches out_end (which has NUL already)
}
However, this is exactly as many loop iterations so it is not any faster, and it is much less clear code, so don't do this in real code...
I want to replace all occurrences in an array (string) with another array.
I have a code that:
stores the string in an array in which the replacing is to take place output[],
another array that stores the string to be searched for as replace[] and a third array called toBeReplacedBy and the replacing of the first occurrence works just fine but it skips the other occurrences in the output
for example:
replace[]:
abc
toBeReplacedBy[]:
xyz
output[]:
abcdefabc
becomes
xyzdefabc
but it should become:
xyzdefxyz
I suspect the problem lies with the replacer code :
//the replacer
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
//debug purpose
puts("output[]:\n");
puts(output);
return 0;
}
What have I done wrong here and how could I get it to replace all occurrences in the array.
please be aware that I only wish to use stdio.h to do this
thabks in advance
Never iterate further than the array length. This leads to undefined and possibly dangerous behaviour. If you only expect strings, use something like:
int i = 0;
while(output[i] != '\0')
{
// your logic here
i++;
}
Additionally you want to check for concurrent appearances of the same characters. But in your code you only check the first three characters. Everything after that is undefinded behaviour, because you cannot know what replace[3] returns.
Something similar to this could work:
int i = 0;
int j = 0;
int k;
while(output[i] != '\0')
{
if (output[i] == replace[j])
j++;
else
j = 0;
// replace 3 with the array length of the replace[] array
if (j == 3)
{
for(k = i; j >= 0; k-- )
{
output[k] = toBeReplacedBy[j]
j--
}
j = 0;
}
i++;
}
But please check the array boundaries.
edit: Additionally as Nellie states using a debugger would help you to understand what went wrong. Go through your program step by step and look how and when values change.
First advice is to try to debug your program if it does not work.
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
There are two problems in this loop.
The first is that are iterating until i is 80. Let's look what happens when i becomes 3. output[3] in case of abcdefabc is d, but what is replace[3]? Your replacement array had only 3 letters, so you have to go back in the replacement array once you finish with one occurrence of it in the original string.
The second is that you check letter by letter.
Say you original array, which you named output somehow was abkdefabc, first three letters do not match your replacement string, but you will check the first two letters they will match with the replacement's first two letters and you will incorrectly change them.
So you need to first check that the whole replacement string is there and only then replace.
You should use strlen() to know length of your array or iterate until you reach the end of a your array ('\0').
'\0' and strlen are only available for array of char.
Your loop should looks like this :
int i = 0;
int len = strlen(my_string);
while (i < len)
{
//logic here
i = i + 1;
}
OR
int i = 0;
while (my_string[i] != '\0')
{
// logic here
i = i + 1;
}
This is a program to find the largest even number and its times of occurring from an input file and output it to an output file. I'm having a problem with the output, there seems to be an extra iteration that messes things up.
int main(int argc, char const *argv[])
{
int n, num, i, even, count;
FILE * fptr;
FILE * fptro;
fptr =fopen("maximpar.in", "r");
fptro=fopen("maximpar.out", "w");
/*scanning the first line from the file to get n for for()*/
fscanf(fptr, "%d", &n);
count = 0;
even = INT_MIN;
for(i = 0; i < n; i++)
{
fscanf(fptr, "%d", &num);
if( (num % 2 == 0 && num > even) || (even == num) )
/*checking for largest even number,
not sure about the ..||(even == num) part of the condition*/
{
even = num;
count++;
}
}
fprintf(fptro, "%d %d", even, count);
fclose(fptr);
fclose(fptro);
return 0;
}
Input file
6
9 6 9 8 9 8
Output file
8 3
Why isn't the output file like this? I don't understand
8 2
You need to reset your count whenever you get a new larger number.
I didn't test this, but it should work:
cate = 0;
par = INT_MIN;
for (i = 0; i < n; i++) {
fscanf(fptr, "%d", &b);
// skip odd numbers
if ((b % 2) != 0)
continue;
// get new larger number
if (b > par) {
par = b;
cate = 1;
continue;
}
// increment count on existing largest number
if (b == par)
++cate;
}
UPDATE:
I dont understand why skip iterations explicitly instead of only picking out the iterations that matter? Is there some sort of advantage?
Yes, it's better style. It allows simple single level indented if statements that can have their own comments.
It avoids a messy compound if or a triple level if/else ladder.
IMO, it's a common misconception [particularly among beginning C programmers] that a complex if will execute faster [or is somehow "better"] than several simple ones.
The first if could be thought of a "skip this iteration" test. Here, there's only one. But, for more complex code, there might be several.
The multiple condtion escapes could be handled in a single if with if (c1 || c2 || c2 || ... || c10) continue; but that gets messy fast.
Herein, for properly indented if/else ladder logic, we'd need:
if (cond1)
do_stuff1;
else
if (cond2)
do_stuff2;
else
if (cond3)
do_stuff3;
If we're not in a loop, here's a "trick" to avoid if/else ladder logic, by using do { ... } while (0);:
do {
if (cond1) {
do_stuff1;
break;
}
if (cond2) {
do_stuff2;
break;
}
if (cond3) {
do_stuff3;
break;
}
} while (0);
enclose the condition
if( ( ...&&...) ||(....) )
The answer is because count was incremented from 0 to 1 when b = 6. 2 iterations later, b = 8 and now count = 2, and 2 iterations after that, b = 8 and count = 3.
I also recommend you nest your if statement in parentheses for readability. Commenting would help too :) I'm a stats guy, and I have no idea what you are doing based on your variables' names.
You need to reset your counter inside the if block if b > par.
Like:
if( num % 2 == 0 && num >= even) {
if (num > even){
even = num;
count = 1;
} else {
count++;
}
}
Thanks.
JK
I want to remove any spaces from the user input and give the result back on the screen. So far, the following is my working solution. I haven't noticed any errors yet. Since I'm pretty new to C and programming in general, my question is: Is there something I can do better? Anything to optimize or something? I appreciate any tips from you guys since you are probably a lot more experienced than I am. So, here's my code:
#include <stdio.h>
#include <string.h>
#define PUFFERGROESSE 100
#define ERROR 1
#define OK 0
int main(){
char stringPuffer[PUFFERGROESSE];
printf("Please enter some words:"); fflush(stdout);
if(fgets(stringPuffer, PUFFERGROESSE, stdin) == NULL){
printf("Unable to read.\n");
return ERROR;
} else {
char endString[PUFFERGROESSE];
for (int i = 0, j = 0; i < PUFFERGROESSE; i++, j++) {
if (stringPuffer[i] != ' ' ) {
endString[j] = stringPuffer[i];
} else {
j--;
}
}
printf("Without spaces your input looks like that: %s", endString);
}
}
In your code, the for loop condition is i < PUFFERGROESSE. Inside this loop, you access stringPuffer using the loop index.
Now, stringPuffer being an uninitialized automatic local variable and with a sufficiently small input, a strict check like i < PUFFERGROESSE will cause access to uninitialized memory of stringPuffer, creating undefined behavior.
You can make use of strlen() after taking the user input.
Another note, int main() is better as int main(void), at least.
NITPICK: why's the OK defined, if not used?
Several suggestions:
Initialize endString to all zeros; that way you won't have to worry about string termination issues later on:char endString[PUFFERGROESSE] = {0};
Instead of looping while i is less than PUFFERGROESSE, loop until you see the end of the string:for( int i = 0, j = 0; stringPuffer[i] != 0; i++ )
Also, only increment j when you write the non-space character, rather than incrementing it unconditionally and then having to decrement it when you see a space:if ( !isspace( stringPuffer[i] ) )
endString[j++] = stringPuffer[i];
So basically, that code reduces to:
char endString[PUFFERGROESSE] = {0};
for (int i = 0, j = 0; stringPuffer[i] != 0; i++) {
if ( !isspace( stringPuffer[i] ) ) {
endString[j++] = stringPuffer[i];
}
}
I have to search a substring in a string & display the complete word as given below everytime the substring is found-
eg:
Input: excellent
Output: excellent,excellently
I cannot figure out how to make the output like the one above.
My output:
excellent,excellently,
It always give me a comma in the end.
Prog: desc
Iteratively convert every words in the dictionary into lowercase,
and store the converted word in lower.
Use strncmp to compare the first len characters of input_str and lower.
If the return value of strncmp is 0, then the first len characters
of the two strings are the same.
void complete(char *input_str)
{
int len = strlen(input_str);
int i, j, found;
char lower[30];
found = 0;
for(i=0;i<n_words;i++)
{
for(j=0;j<strlen(dictionary[i]);j++)
{
lower[j] = tolower(dictionary[i][j]);
}
lower[j+1]='\0';
found=strncmp(input_str,lower,len);
if(found==0)//found the string n print out
{
printf("%s",dictionary[i]);
printf(",");
}
}
if (!found) {
printf("None.\n");
} else {
printf("\n");
}
}
Check if you have already printed a word before printing a second one:
char printed = 0;
for (i=0; i < n_words; i++)
{
for(j = 0; j < strlen(dictionary[i]); j++)
lower[j] = tolower(dictionary[i][j]);
lower[j + 1] = '\0';
found = strncmp(input_str, lower, len);
if (found == 0)//found the string n print out
{
if (printed)
printf(",");
printf("%s", dictionary[i]);
printed = 1;
}
}
There are two approaches that I tend to use for the comma-printing problem:
At the start of the loop, print the comma if i > 0.
At the end (after printing the real value), print the comma if i < (n - 1).
You can use either, the first is simpler since the comparison is simpler, but it can be slightly less convenient since it moves the comma-printing in time (!). On each loop iteration, you're printing the comma that belongs to the previous iteration. At least that how it's feels to me, but of course it's rather subjective.