String modification through function. Unexplained behavior - c

This Program should change n't followed by an alphabet to " not". like don't -> do not.
But it's showing some really weird outputs.
e.g if i just skip printing the string length output is garbage. also how space is changing to s2ace in output i can't say. If i didn't know better i'd say i have a ghost in the code.
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int func(char **str, int cur_len, int max_len)
{
if (cur_len <= 3)
return(cur_len);
else if(max_len < cur_len)
return(-1);
int i,j;
char new[max_len];
new[0]='\0';
char temp[2];
for (i = 0; i < cur_len; i++)
{
if(i > 0 && i < cur_len - 2 && isalpha((*str)[i-1]) && (*str)[i] == 'n' && (*str)[i+1] == '\'' && (*str)[i+2] == 't')
{
strcat(new," not");
i=i+2;
}
else
{
temp[0]=(*str)[i];
temp[1]='\0';
strcat(new, temp);
}
}
j = strlen(new);
if (j > max_len)
return(-1);
*str = new;
return(j);
}
int main()
{
char *x = "Please don't do anything stupid. all the n't followed by an alphabate should be changed to not followed by a space. e.g. doesn't.";
int len, max, result;
len = strlen(x);
printf("String size = %d\n",len);//**if i comment this line all output goes down the drain.**
max = 200;
result = func (&x, len, max);
if(result == -1)
{
printf("No change possible\n");
return(-1);
}
printf("No of changes = %d\n",strlen(x)-len);
printf("New String is :: %s\n",x);//**how does space change into s2ace??**
return(0);
}
Output is
129No of changes = 2
New String is :: Please do not do anything stupid. all the n't followed by an alphabate should be changed to not followed by a s2ace. e.g. does not.

Fix the problem with minimal code changes by replacing char new[max_len]; with
char *new = *str = (char*)malloc(max_len+1);
You'll also need to add #include <stdlib.h> at the top.
As mentioned in comments, pointers to local objects (with auto storage class) become invalid as soon as the function returns.
Static objects won't disappear, but I don't believe that variable-length arrays are allowed to be static. So, you're stuck with malloc/calloc.
Be sure to document this behavior, so that the author of the calling function knows to free the pointer when the memory is no longer needed. (If you're going to quibble that you are the author and already know it, I'll point out that it helps the reader of your code to know what's going on.)

Related

Put characters from a char array in a string till a specific character is found

I'd like a reliable method to read the characters from a character array and put them in a string. This will happen till a \r is found. I can iterate through the array but have no good way to put that in a string. I am afraid to use malloc since, at times, puts garbage value in a string.
Here payload is the HTTP data from a TCP packet. \r\n\r\n indicates the end of the payload.
My code so far to iterate through the character array:
void print_payload(const unsigned char *payload, int len) {
int i;
const unsigned char *ch = payload;
for (i = 0; i < len; i++) {
if (strncmp((char*) ch, "\r\n\r\n", 4) == 0) {
// Indicates end of payload data.
break;
} else if (strncmp((char*) ch, "\r\n", 2) == 0) {
//Indicates EOL
printf("\r\n");
ch++;
i++;
} else if(strncmp((char*) ch, "Host:", 5) == 0){
printf("Host: ");
const unsigned char *del = ch + 6;
int i = 0;
while (del[i] != 13 ){
/*
*13 is decimal value for '\r'.
* The characters below are to be inserted
* in a string. Not sure how though.
*/
printf("%c",del[i]);
i++;
}
} else if(strncmp((char*) ch, "User-Agent: ", 11) == 0){
/*
* It has to implemented here as well.
* And in every case where my string matches.
*/
printf("UserAgent: ");
const unsigned char* del = ch + 11;
int i = 0;
while(del[i] != 13){
printf("%c")
}
}
ch++;
}
printf("\r\n\r\n");
printf("\n");
return;
}
Can somebody help me achieve this? I know this is basic but I'm still learning C Programming and am not sure how to do this. Thank in advance.
You have a few options. First, if you can limit the size of the string, and do not need it outside of the function, then a char array would work:
#define STRING_MAX_LEN 999//chux mentions this is better then just putting "1000" in the array[] - 1000 needs to make sense in terms of the program, or something you wish to enforce (and checked!)
char newString[STRING_MAX_LEN+1] = {0};//Initialize to NULL value.
There is no reason to fear malloc though - just remember to work safely and free, and you should be fine:
char *newString = malloc(sizeof(char)*(len+1)); //Better limit on needed space - +1 for a final '\0'.
if (!newString) //Oh no! hard fail.
//do Something
}
memset(newString,0,sizeof(char)*(len+1)); //No garbage in my new string anymore!
...
...
free(newString);
//Finish up with program
You will not even have to append a '\0' - you are already sure the buffer is full of them, so you a valid C string. Note sizeof(char) may be redundant but I like to keep it anyway, in case one day it will not equal 1.
Note if you have to return the new string for some reason you must use a dynamically allocated array, using malloc. Finally, if you only need to check/hold one sub-string at a time, then re-using the same string is preferable.
void print_payload(const unsigned char *payload, int len)
{
int i;
char c;
char *p;
p = (char*)payload;
for(i=0;i<len;i++) {
if(!strncmp(&p[i],"\r\n\r\n",4)) {
c = p[i+4];
p[i+4] = 0;
break;
}
}
if(i==len) {
return;
}
printf("%s\n",p);
p[i+4] = c;
}

C programming, meaningless figures on console [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I wrote code to reverse a sentence that the user inputs, but when I run this code and write a sentence, this code prints meaningless figures instead of reverse version of my sentence. I need helping locating the error
#include <stdio.h>
#include <string.h>
void reverser(char*);
int readmassage(char[], int);
int main()
{
char mysentence[30];
readmassage(mysentence, 30);
reverser(mysentence);
printf("%s", mysentence);
system("pause");
return 0;
}
void reverser(char *massage)
{
char temp,*p;
p = massage + strlen(massage)-1;
while (p > massage) {
temp = *massage;
*massage = *p;
*p-- = temp;
}
}
int readmassage(char massage[], int lenght)
{
int ch, i = 0;
while (ch = getchar() != '\n') {
if (lenght > i)
massage[i++] = ch;
}
massage[i] = '\0';
return i;
}
Your problem is here:
temp = *massage;
*massage = *p;
*p-- = temp;
massage always points to the first character in your string here. So you keep overwriting the first character, and then writing the new first character to the last character on the next go round. The effect is that you essentially rotate the string by one character instead of reversing it. If you change *massage = *p; to *massage++ = *p; (or create a new incrementing pointer variable to correspond to p which you initialize to massage), it'll probably work.
What I'm saying is that your "start of the string" pointer needs to be... massaged. ba dum chshhhh
EDIT: And you also need to change this, in readmessage:
while (ch = getchar() != '\n')
to:
while ((ch = getchar()) != '\n')
Otherwise, rather than the input character, you're actually setting ch to 0 or 1, depending on whether getchar() is returning '\n' or not. This is because due to the order of operations, != actually gets executed before =, and != gives you 1 if the expression is true and 0 if it is false. This 0 or 1 then gets stored in ch by the = operator.
You could also just replace all of readmessage with fgets, as it's included in the standard library and meant for exactly this sort of thing (unless reimplementing it was part of your assignment, of course).
EDIT:
Adding explanation. There are some issues with your code, few major, few not that serious
Don't use void main(). It's not the best thing to use.
Indenting your code will make it easier to read
Let's look at the readmassage function.
You are assigning the result of getchar() to an int. That's not right. it should be a char
here's a version of your code with minor fixes
#include <stdio.h>
#include <string.h>
void reverser(char*);
int readmassage(char[], int);
void main()
{
char mysentence[30];
readmassage(mysentence, 30);
printf("Input: %s", mysentence);
reverser(mysentence);
printf("Output: %s", mysentence);
system("pause");
return 0;
}
void reverser(char*massage)
{
char temp,*p;
p = massage + strlen(massage)-1;
while (p > massage) {
temp = *massage;
*massage = *p;
*p-- = temp;
}}
int readmassage(char massage[], int lenght)
{
char ch;
int i = 0;
while (ch != '\n')
{
ch = getchar();
printf("Here\n");
if (lenght > i)
{
massage[i++] = ch;
printf("%c\n", massage[i]);
}
}
massage[i] = '\0';
return i;
}
When you try this you will find that the input string gets read fine, just be sure to not to hi Enter after every character and instead type the full string out as \n is a valid character that can be in the stream and will terminate the loop the next iteration.
This is why you should use a char array reading function like fgets.
Once you get here you can see that the reverser is just following a slightly flawed reversing logic.
grammatical errors aside, fixing this you can get
here you go
#include <stdio.h>
#include <string.h>
void reverser(char* message)
{
int start, end;
start = 0;
end = strlen(message) - 1;
char temp;
while (start < end) {
temp = message[start];
message[start] = message[end];
message[end] = temp;
start++;
end--;
}
}
void readmessage(char message[], int length)
{
fgets(message, length , stdin);
}
int main()
{
char mysentence[30];
readmessage(mysentence, 30);
printf("Read the string\n");
reverser(mysentence);
printf("%s\n", mysentence);
return 0;
}
please debugg to find out the reason sometimes.. It will help you..
The problem is when you call readmassage(mysentence, 30) inside the function you have the string input.
When the flow comes back to the method the value is no more there as you had passed mysentence by value..
And you send null to reverse()..
Pass by reference will work..

Replacing `goto` with a different programming construct

I m trying to do this little programm with defensive programming but its more than difficult for me to handle this avoiding the Loop-Goto as i know that as BAD programming. I had try with while and do...while loop but in one case i dont have problem. Problem begins when i m going to make another do...while for the second case ("Not insert space or click enter button"). I tried and nested do...while but here the results was more complicated.
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i;
int length;
char giventext [25];
Loop:
printf("String must have 25 chars lenght:\n");
gets(giventext);
length = strlen(giventext);
if (length > 25) {
printf("\nString has over %d chars.\nMust give a shorter string\n", length);
goto Loop;
}
/* Here i trying to not give space or nothing*/
if (length < 1) {
printf("You dont give anything as a string.\n");
goto Loop;
} else {
printf("Your string has %d\n",length);
printf("Letter in lower case are: \n");
for (i = 0; i < length; i++) {
if (islower(giventext[i])) {
printf("%c",giventext[i]);
}
}
}
return 0;
}
Note that your code is not defensive at all. You have no way to avoid a buffer overflow because,
you check for the length of the string after it has been input to your program so after the buffer overflow has already occurred and
you used gets() which doesn't check input length and thus is very prone to buffer overflow.
Use fgets() instead and just discard extra characters.
I think you need to understand that strlen() doesn't count the number of characters of input but instead the number of characters in a string.
If you want to ensure that there are less than N characters inserted then
int
readinput(char *const buffer, int maxlen)
{
int count;
int next;
fputc('>', stdout);
fputc(' ', stdout);
count = 0;
while ((next = fgetc(stdin)) && (next != EOF) && (next != '\n')) {
// We need space for the terminating '\0';
if (count == maxlen - 1) {
// Discard extra characters before returning
// read until EOF or '\n' is found
while ((next = fgetc(stdin)) && (next != EOF) && (next != '\n'))
;
return -1;
}
buffer[count++] = next;
}
buffer[count] = '\0';
return count;
}
int
main(void)
{
char string[8];
int result;
while ((result = readinput(string, (int) sizeof(string))) == -1) {
fprintf(stderr, "you cannot input more than `%d' characters\n",
(int) sizeof(string) - 1);
}
fprintf(stdout, "accepted `%s' (%d)\n", string, result);
}
Note that by using a function, the flow control of this program is clear and simple. That's precisely why goto is discouraged, not because it's an evil thing but instead because it can be misused like you did.
Try using functions that label logical steps that your program needs to execute:
char * user_input() - returns an input from the user as a pointer to a char (using something other than get()! For example, look at scanf)
bool validate_input(char * str_input) - takes the user input from the above function and performs checks, such as validate the length is between 1 and 25 characters.
str_to_lower(char * str_input) - if validate_input() returns true you can then call this function and pass it the user input. The body of this function can then print the user input back to console in lower case. You could use the standard library function tolower() here to lower case each character.
The body of your main function will then be much simpler and perform a logical series of steps that tackle your problem. This is the essence of defensive programming - modularising your problem into separate steps that are self contained and easily testable.
A possible structure for the main function could be:
char * user_input();
bool validate_input(char *);
void str_to_lower(char *);
int main()
{
char * str_input = user_input();
//continue to get input from the user until it satisfies the requirements of 'validate_input()'
while(!validate_input(str_input)) {
str_input = user_input();
}
//user input now satisfied 'validate_input' so lower case and print it
str_to_lower(str_input);
return 0;
}

Storing values of file into array leads to weird behaviour

Let's say I've got the file
5f2
3f6
2f1
And the code:(The printf should print the second numbers (i.e 2,6, and 1) but it doesn't
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, char * argv[])
{
FILE *ptr;
char str[100];
char * token;
int a, b, i;
int arr[4];
if(argc > 1)
{
ptr = fopen(argv[1],"r");
if(ptr == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
//And I'm looking to parse the numbers between the "f" so..
while(fgets(str,100,ptr) != NULL)
{
token = strstr(str,"f");
if(token != NULL)
{
a = atol(str); // first number
b = atol(token+1); // second number
arr[i] = b; // store each b value (3 of em) into this array
}
i++;
printf("Values are %d\n",arr[i]); //should print 2,6 and 1
}
}
I've tried to move the printf outside the loop, but that seems to print an even weirder result, I've seen posts about storing integers from a file into an array before, however since this involves using strstr, I'm not exactly sure the procedure is the same.
int i,j=0;
while(fgets(str,sizeof(str),file) != NULL)
{
size_t n = strlen(str);
if(n>0 && str[n-1] == '\n')
str[n-1] = '\0';
i = str[strlen(str)-1] - '0'; /* Convert the character to int */
printf("%d\n",i);// Or save it to your int array arr[j++] = i;
}
Just move to the last character as shown and print it out as integer.
PS: fgets() comes with a newline character you need to suppress it as shown
You are never initializing i, then you are reading into arr[i] (which just happens to not crash right there), then increment i (to "undefined value + 1"), then print arr[i] -- i.e., you are writing to and reading from uninitialized memory.
Besides, your FILE * is ptr, not file. And you should get into the habit of using strtol() instead of atol(), because the former allows you to properly check for success (and recover from error).

scanf catches char type string with \0 and bunch of zeros after in C

I'm working on enumerations in C and can't find the source of problem in the following example that, the output is always "Sorry!":
#include <stdio.h>
#include <stdlib.h>
typedef enum
{
summer, winter, fall, spring
} season;
void printPhrase (season s);
int main(void)
{
printf("What's your prefered season? ");
char seasonHold[10], seasonHold2[10];
scanf("%s", seasonHold);
for (int n = 0; n < strlen(seasonHold); n++)
{
if (n != '\0')
seasonHold2[n] = seasonHold[n];
}
printPhrase (*seasonHold2);
return 0;
}
void printPhrase (season s)
{
if (s == summer)
printf("It's hot out!\n");
else if (s == fall)
printf("It's getting cooler!\n");
else if (s == winter)
printf("Should be really cold!\n");
else if (s == spring)
printf("It should be lovely outside!\n");
else
printf("Sorry!\n");
}
The problem is whatever input I enter, there's always one output: Sorry!
Thanks.
Also, this can solve the matter:
I could manage it by changing main function into following:
int main(void)
{
printf("What's your prefered season? ");
char seasonHold[10];
scanf("%s", seasonHold);
if (seasonHold[0] == 's')
printPhrase (summer);
else if (seasonHold[0] == 'f')
printPhrase(fall);
else if (seasonHold[1] == 'p')
printPhrase(spring);
else if (seasonHold[0] == 'w')
printPhrase(winter);
return 0;
}
Enums are like constant integers. Here: summer=0, winter=1,...
seansonhold is a char*. By dereferencing it you get a char. This char will then be converted to a 'season' type because char->int does not give compiler errors.
So you basically test here if the first byte of your char array is equal to 0,1,2..
If you are sure seasonHold is null-terminated (it will be here), you can use a pointer and while loop to accomplish what you want:
char *ptr = seasonHold;
n = 0;
while (*ptr++) { /* same as saying while (*ptr++ != '\0') */
seasonHold2[n] = seasonHold[n]; /* could also do: seasonHold2[n] = *ptr; */
n++;
}
seasonHold2[n] = 0; /* null-terminate */
Additionally, if you would like to dynamically allocate seasonHold2, you can simply declare it as a pointer, include string.h and use strdup to copy seasonHold to seasonHold2, e.g.:
#include <string.h>
...
char *seasonHold2;
...
seasonHold2 = strdup (seasonHold);

Resources