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];
}
}
Related
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).
Basically I am creating an array 'string' with some values in it, creating another array ('auxstring'), and then storing all the values of the initial array in reverse order. Finally I print them out.
How come when I execute the program as is, I get garbage as the output? However, if I put another number in the 'string' array (ie: {3,1,1,3,4}) it works fine (outputs: 43113).
It also works fine if I add this line:
"printf("%d\n", sizeof(auxstring));"
right before the for loop.
I'm sure it's something very basic, but I would like to understand what is going on behind the scene and why adding a number at the end of the initial string, or putting that printf, somehow outputs the accurate numbers.
Thanks.
#include <stdio.h>
#include <string.h>
int main(void) {
int i=0, j, l;
char string[] = {3,1,1,3};
char auxstring[sizeof(string)];
for (j=(sizeof(auxstring) - 1); j >= auxstring[0]; j--) {
auxstring[j] = string[i];
i++;
}
for (l=0; l < sizeof(auxstring); l++) {
printf("%d",auxstring[l]);
}
return 0;
}
The condition in the for loop
for (j=(sizeof(auxstring) - 1); j >= auxstring[0]; j--) {
^^^^^^^^^^^^^^^^^^
does not make sense because at least the array auxstring is not initialized.
Also the loop is complicated because it uses two variables as indices.
Ans the variables i, j, l should have the type size_t - the type of the returned value of the operator sizeof.
The program can look the following way
#include <stdio.h>
int main(void)
{
char string[] = { 1, 2, 3, 4 };
char auxstring[sizeof( string )];
const size_t N = sizeof( string );
for ( size_t i = 0; i < N; i++ )
{
auxstring[i] = string[N - i - 1];
}
for ( size_t i = 0; i < N; i++ )
{
printf( "%d", auxstring[i] );
}
return 0;
}
Its output is
4321
The loop condition should be j >= 0.
Right now you compare against the uninitialized value in auxstring[0], which is indeterminate (and will seem random).
I've tried this code but it doesn't seem to be working, how to break out of the nested loop ?
#include <stdio.h>
#include <string.h>
int meme(char s1[], char s2[])
{
int i = 0, j = 0;
int different;
while (i <= strlen(s1) && different == 1) {
while (j <= strlen(s2)) {
if (s1[i] != s2[j]) {
different = 1;
} else {
different = 0;
}
j = j + 1;
}
i = i + 1;
}
return different;
}
You have to initialize different as it is undefined if not - this probably breaks your first while loop as different probably is a random number > 1.
strlen gives you the number of characters in the string excluding the null-character which terminates the string (see here). However, you do not only compare the characters of the two strings, but also the null-character, probably to implicitely check if the length of the strings is the same. While this should work, it is better to do this check explicitely by comparing the length of the strings first as it is less error-prone.
It isn't necessary to do a nested loop here if you compare the length of the strings first. Also, you now know the length of both strings, so this function can be change to use a for loop, which makes it even simpler.
A possible solution based on the points above:
#include <stdio.h>
#include <string.h>
int meme(char s1[], char s2[]){
int i = 0;
int len_s1 = 0;
int len_s2 = 0;
int different = 0;
len_s1 = strlen(s1);
len_s2 = strlen(s2);
if (len_s1 == len_s2) {
for (i = 0 ; i < len_s1 ; i++) {
if (s1[i] != s2[i]) {
different = 1;
break;
}
}
else {
different = 1;
}
return different;
}
One more thing - do yourself and everyone else a favor and intend your code as it is extremely hard to read otherwise!
Your code is not optimized and you are not using a good approach for doing the task. I have modified the code and it will do the job with minimized complexity.
Here I assume that both the arrays are of same size as your problem shows
bool meme(char s1[], char s2[])
{
int i=0;
while(s1[i] != NULL && s2[i] != NULL)
{
if(s1[i] == s2[i])
return false;
i += 1;
}
return true;
}
When you call this function then declare a variable of type bool and store the returned value of this function in that variable.
For example :
bool check;
bool = meme(array 1 , array 2);
and then check if returned value is true, then both the arrays are totally different else not. You can do that by the below code :
if(check)
printf("Arrays are different");
else
printf("Arrays are not different");
You can also use int in place of bool if it suits you better but remember, whatever code you write, must be least complex. And think that if you are using int then also you are returning only 0 or 1; but int takes 2 bytes in 32-bit compiler and 4 bytes in 64-bit compiler, but bool takes only 1 byte and even 1 bit in some languages like pascal (if I am not wrong).
And don't get confused with return true; and return false;. True simply means 1 and false means 0. And a boolean type variable can store only binary number (1 or 0).
There is so much wrong with your code.
Why are you calling strlen() in while()? It will get executed every time till the loop doesn't exit and will cost on performance.
Also the variable different is not initialized with value 1, so how can you be so sure about the initial value of that variable?
I have tried to simplify your function still, there is scope for optimization:
int meme(char s1[], char s2[])
{
int i = 0;
int different;
int str1_len = strlen(s1);
int str2_len = strlen(s2);
if(str1_len > str2_len)
str1_len = str2_len;
do{
if(s1[i] == s2[i])
{
printf("Common\n");
different = 0;
}
else
{
different = 1;
}
i++;
}while(str1_len--);
return different;
}
So I'm trying to load the s-records from a .s19 file into memory for an assignment I'm working on, and its working. However, when I delete an unused array from my code, everything stops working and crashes.
The unused array is:
char test[65536];
And this is the loader I've written:
void loader(FILE * srec)
{
char instring[SREC_LEN];
char test[65536]; // This isn't used, but the program crashes without it for some reason
int i=0;
int j=0, k,l;
while (fgets(instring, SREC_LEN, srec) != NULL)
{
while(instring[i] != '\n') // Counts the characters in the s-record
{
i++;
}
j = j+i;
for(k=0;k<=i;k++) // Puts the records into memory
{
memory[l] = instring[k];
l++;
}
l = j;
}
#ifdef DEBUG
printf("MEMORY: %s",memory);
#endif // DEBUG
}
If you could help me to understand why this is happening, I would appreciate it.
Your code has undefined behavior, it only works by sheer luck:
fgets() may return without writing a newline character into the buffer if EOF is reached prematurely. So you should at least account for that in your loop. Also you never reset i to 0, which you should. Change this:
while(instring[i] != '\n') // Counts the characters in the s-record
{
i++;
}
to:
i = 0;
while(instring[i] != '\n' && instring[i] != '\0') // Counts the characters in the s-record
{
i++;
}
l is never initialized; you are probably writing out of bounds in memory. Initialize l to 0:
int j = 0, k, l = 0;
(I assume that memory is large enough to hold everything).
It also looks to me like you want for(k = 0; k < i; k++) rather than for(k = 0; k <= i; k++), since i is the count of characters you want to copy.
You might want to use memcpy() instead.
Well, I've been at this forever and I know exactly where the fault is, but no clue how to fix it. I already know fgets and scanf would be better for this program, but I can't do that.
The program worked about 10 minutes ago, then I changed it and got a seg fault. Then I changed it back and still got a seg fault. Anyway, I'm sure the fresh eyes will see it right away. Have at it :D
PS: Please note my (lessthan) instead of < because I don't know how to properly leave those in my code examples still :(
#define WORDLENGTH 15
#define MAXLINE 1000
int main()
{
char *line[MAXLINE];
int i = 0;
int j;
int n;
char c;
for (n=0; c!=EOF; n++){
char *tmp = (char *) malloc(sizeof(char)*WORDLENGTH);
while ((c=getchar())!=' ')
tmp[i++]=c;
line[n]=tmp;
i=0;
printf("\n%s\n",line[n]); //
}
for(j = 0; j < n; j++){
printf("\n%s\n", line[j]);
free (line[j]);
}
return 0;
}
you are doing line[n++] = tmp. And then accessing line[n] after that. But line[n] hasn't been assigned.
To change it, you can print line[n-1] instead, but clearer would be:
line[n] = tmp;
i = 0;
printf(... line[n]);
and place the increment in the for statement instead i.e. for (n = 0; c != EOF; n++).
EDIT
This is a summary of what I would do:
Place the i=0 assignment at the start of the loop. Logically, it is an initialization of i and currently it is done in two places (at int i = 0; and after the assignment of line[n]). Both places are not near where one would expect an initialization of a variable used in the while loop to be.
Guard against nonsense input by checking that i does not exceed WORDLENGTH-1. Actually, I would probably code the inner while loop as a for loop on i like so:
for (i = 0; i < WORDLENGTH; i++) {
tmp[i] = getchar();
if (tmp[i] == ' ') break;
}
tmp[i] = 0;
or (in my character) for(i = 0; i < WORDLENGTH; ++i) if ((tmp[i] = getchar()) == ' ') break; followed by..
tmp[i] = 0 to NUL-terminate the string. Since malloc doesn't necessarily return a 0-filled memory block.
there are still bugs in the suggested solution !
malloc() can fail and return a NULL pointer
at the end of the for () the maximum i value is WORDLENGTH
so this assignment isn't correct ( out of bounds )
tmp[i]= 0;
Can fix both with
char *tmp = (char *) malloc( sizeof(char) * (WORDLENGTH + 1) );
if ( tmp == NULL ) // end of available memory
break;
moreover, it isn't clear if you allow EOF inside the last string.