Why is strlen causing a segmentation fault in C? - c

(Warning) Yes this is a part of an assignment I am working on, but I am completely desperate at this point and NO I am not looking for you guys to solve it for me, but any hint would be much appreciated!(/Warning)
I am pretty much trying to make an interactive menu, the user is meant to input an expression (For example "5 3 +") and the program should detect that it's in postfix notation, unfortunately I have been getting segmentation fault errors and I suspect they have something to do with the use of the strlen function.
EDIT: I was able to make it work, first the char expression[25] = {NULL}; line
becomes char expression[25] = {'\0'};
And when calling the determine_notation function I removed the [25] from the array I am passing like so:
determine_notation(expression, expr_length);
Also the input[length] part I changed to input[length-2] since like mentioned in a previous comment, input[length] == '\0' and input[length--] == '\n'.
All in all thanks for all the help!
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int determine_notation(char input[25], int length);
int main(void)
{
char expression[25] = {NULL}; // Initializing character array to NULL
int notation;
int expr_length;
printf("Please enter your expression to detect and convert it's notation: ");
fgets( expression, 25, stdin );
expr_length = strlen(expression[25]); // Determining size of array input until the NULL terminator
notation = determine_notation( expression[25], expr_length );
printf("%d\n", notation);
}
int determine_notation(char input[25], int length) // Determines notation
{
if(isdigit(input[0]) == 0)
{
printf("This is a prefix expression\n");
return 0;
}
else if(isdigit(input[length]) == 0)
{
printf("This is a postfix expression\n");
return 1;
}
else
{
printf("This is an infix expression\n");
return 2;
}
}

You probably got a warning explaining that you are converting a char to a pointer in this call:
expr_length = strlen(expression[25]);
// ^^^^
This is the problem - your code is referencing a non-existent element past the end of the array (an undefined behavior) and tries to pass it to strlen.
Since strlen takes a pointer to the beginning of the string, the call needs to be
expr_length = strlen(expression); // Determining size of array input until the NULL terminator

Related

Pointers and char arrays from strings

Hi I have been reading for hours and still can't grasp the conversions between
{
char i ="adf";
char foo[];
char bar[256];
}
and adding * and & makes it more confusing
I have some code that is working.
int TX_SEND(char send[])
{
unsigned char *p_tx_buffer;
p_tx_buffer = &send[0];
strcat(send, "\r");
// Write to the port
int n = write(fd,&send[0],3);
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
code is working but I need help with 2 parts.
I want to be able to run this function like kind of like printf IE TX_SEND("AT+CGMSD=STUFF"); but I am stuck
but before hand I do this alot.
char txsend[] = "at";
TX_SEND(txsend);
Also inside my TX_WRITE() I am using write(fd,&send[0],3), but it is hardcoded to send 3 bytes from send[]. I want this to be dynamic so I can just send strings at any length (realistically they will be less than 300 ASCII chars always). I tried to do something with a pointer in there but gave up (*p_tx_buffer was my beginning attempt).
i think you want
int TX_SEND(char *send)
{
int n = write(fd,send,strlen(send));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
you cannot tack on \n to send with strcat. I would add it in the calling function, or declare an intermediate buffer and sprintf to it
like this
int TX_SEND(char *send)
{
char buff[50]; // i dont know a good max size
snprintf(buff, sizeof(buff), "%s\n", send);
int n = write(fd,buff,strlen(buff));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
I'm not going to go through your code line-by-line, but I urge you to focus on these facts:
chars are chars and strings are strings, and never the twain shall meet. (They're totally different.)
'x' is a character constant.
"x" is a string constant.
A string is an array of characters (terminated by '\0').
When you mention an array (including a string) in a context where you need its value, what you get is a pointer to the array's first element.
When you put a & in front of something, what you get is a pointer to that something.
When you put a * in front of a pointer, what you get is the thing that the pointer points to.
Putting this together, we could write
char str[] = "xyz";
char *p = str; /* per rule 5, this is fine, and p gets a pointer to str's first element */
char c = *p; /* per rule 7, c gets the first character of str, which is 'x' */
printf("%c\n", c);
If you're just starting with C, you may not have come across rule 5 yet. It will probably surprise you at first. Learn it well, though: you'll never understand arrays and pointers in C without it.

Why does the online judge fail to accept it?

When I submit a code in the below given format the online judge(of Codechef ) does not accept it:
#include<stdio.h>
int main()
{
int length,test;
char check[26]="zyxwvutsrqponmlkjihgfedcba";
scanf("%d",&test);
while(test--){
scanf("%d",&length);
if(length%25 != 0)
printf("%s",check+25-(length%25));
length/=25;
while(length--)
{
printf("%s",check);
}
printf("\n");
}
return 0;
}
However when I submit the code in the one given below it is readily accepted. Here all I've done is just made the char array from local to global. Can anyone gimme the reasons for it.
#include<stdio.h>
char check[26]="zyxwvutsrqponmlkjihgfedcba";
int main()
{
int length,test;
scanf("%d",&test);
while(test--){
scanf("%d",&length);
if(length%25 != 0)
printf("%s",check+25-(length%25));
length/=25;
while(length--)
{
printf("%s",check);
}
printf("\n");
}
return 0;
}
Link to the question for which it was used:
http://www.codechef.com/problems/DECSTR
check needs 27 chars to store the string literal (including terminating null) you assigned to it, not 26. Reading off the end is UB, but what's likely happening is in the global-scope version, the next byte happens to be 0, but the local-scope version, the next byte is non-zero, causing an access violation.
You cannot use check (in either version) with "string" functions.
check does not have a terminating NUL byte ('\0') so you invoke Undefined Behaviour.
Hint: leave off the size of the array when initializing with a string literal.
char check[] = "zyxwvutsrqponmlkjihgfedcba"; // compiler determines size automagically

'Scanf' for a String - Program crashing?

Why is this crashing when I input the string? I don't think I'm reading in the string right but the program gives me an error on the first 'scanf.' The program should be correct but this is C not C++. Most help that I could find was for C++.
//Andrei Shulgach
//April 27th, 2015
/*A string is a palindrome if it can be read forward and backward with the same
meaning. Capitalizations and spacing are ignored.*/
#include <stdio.h>
#include <stdlib.h>
int newStrCmp (const char *string1, const char *string2);
int main()
{
//Local Declarations
int dummy, value;
char string1[100],string2[100];
printf("Please enter the 1st string: ");
scanf_s("%99s", string1[100]);
printf("\nPlease enter the 2nd string: ");
scanf_s("%99s", string2[100]);
//Call Function and get value
value = newStrCmp(string1, string2);
if (value == 0)
printf("The strings are equal.\n");
else
printf("The strings are not equal.\n");
scanf_s("%d",&dummy);//Keep Window Open
return 0;
}
int newStrCmp (const char *string1, const char *string2)
{
//Local Declarations
int value = 0;
while (string1[value] == string2[value])
{
if (string1[value] == '\0' || string2[value] == '\0')
break;
value++;
}
if (string1[value] == '\0' && string2[value] == '\0')
return 0;
else
return -1;
}
You must enable all compiler warnings that you can get from your compiler; the above code shouldn't have compiled.
This:
scanf_s("%99s", string1[100]);
invokes undefined behavior since it indexes outside the 100-character string1 array. Remember that C arrays are indexed from 0. It also fails to comply with scanf_s()'s requirement that the size be specified for all string conversions.
It then probably1 causes more undefined behavior, when scanf_f() interprets a single character as a buffer address where input is to be stored (assuming the call happens, of course).
This is not valid code.
It should simply pass the address of the first character in the array:
scanf_s("%99s", string1, sizeof string1);
Here, string1 is the same as &string1[0]; the name of an array evaluates to the address of its first element in many contexts. We then use sizeof string1 as the third argument to specify the size of the string1 buffer, which is required.
1 You cannot reason about what happens after undefined behavior has happened with any certainty.
The issue is you are 'scanf'ing into index 100 of your length 100 buffer, i.e. out-of-bounds.
scanf_s("%99s", string1);
Also your comparison would be safer as a for loop that ensures value is less than 100, rather than a while loop.
In the future, please include the error message.

printf() isn't being executed

I wanted to write a program which counts the occurrences of each letter in a string, then prints one of each letter followed by the count for that letter.
For example:
aabbcccd -
Has 2 a, 2 b, 3 c, and 1 d
So I'd like to convert and print this as:
a2b2c3d1
I wrote code (see below) to perform this count/conversion but for some reason I'm not seeing any output.
#include<stdio.h>
main()
{
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
type=*cp;
cp++;
count=cp;
int c;
for(c=1;*cp==type;c++,cp++);
*count='0'+c;
}
count++;
*count='\0';
printf("%s",array);
}
Can anyone help me understand why I'm not seeing any output from printf()?
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
*cp is a pointer it's pointing to the address of the start of the array, it will never be == to a char '\0' so it can't leave the loop.
You need to deference the pointer to get what it's pointing at:
while(*cp != '\0') {
...
Also, you have a ; after your for loop, skipping the contents of it:
for(c=1;*cp==type;c++,cp++); <-- this ; makes it not execute the code beneath it
After fixing both of those problems the code produces an output:
mike#linux-4puc:~> ./a.out
a1b1c2cd
Not the one you wanted yet, but that fixes your problems with "printf not functional"
Incidentally, this code has a few other major problems:
You try to write past the end of the string if the last character appears once (you write a '1' where the trailing '\0' was, and a '\0' one character beyond that.
Your code doesn't work if a character appears more than 9 times ('0' + 10 is ':').
Your code doesn't work if a character appears more than 2 times ("dddd" doesn't become "d4"; it becomes "d4dd").
Probably line-buffering. Add a \n to your printf() formatting string. Also your code is very scary, what happens if there are more than 9 of the same character in a row?
1) error correction
while(*cp!='\0'){
and not
while(cp!='\0'){
2) advice
do not use array[] to put in your result user another array to put in your rusel it's more proper and eay
I tried to solve your question quickly and this is my code:
#include <stdio.h>
#define SIZE 255
int main()
{
char input[SIZE] = "aabbcccd";/*input string*/
char output[SIZE]={'\0'};/*where output string is stored*/
char seen[SIZE]={'\0'};/*store all chars already counted*/
char *ip = input;/*input pointer=ip*/
char *op = output;/*output pointer = op*/
char *sp = seen;/*seen pointer=sp*/
char c,count;
int i,j,done;
i=0;
while(i<SIZE && input[i]!='\0')
{
c=input[i];
//don't count if already searched:
done=0;
j=0;
while(j<SIZE)
{
if(c==seen[j])
{
done=1;
break;
}
j++;
}
if(done==0)
{//if i never searched char 'c':
*sp=c;
sp++;
*sp='\0';
//count how many "c" there are into input array:
count = '0';
j=0;
while(j<SIZE)
{
if(ip[j]==c)
{
count++;
}
j++;
}
*op=c;
op++;
*op=count;
op++;
}
i++;
}
*op='\0';
printf("input: %s\n",input);
printf("output: %s\n",output);
return 0;
}
It's not a good code for several reasons(I don't check arrays size writing new elements, I could stop searches at first empty item, and so on...) but you could think about it as a "start point" and improve it. You could take a look at standard library to copy substring elements and so on(i.e. strncpy).

Cannot figure this out C programming

The program is supposed to remove everything but the letters and create a new string which will have only the letters in upper-case.
However, it is not printing the results.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *remove_up(char input[])
{
char *new_str = (char *) malloc(strlen(input) + 1);
int i=0;
int j=0;
while (i < strlen(input))
{
if (((input[i]) >= 65 && (input[i]<=90)) || ((input[i]>=97) && (input[i]<=122)))
{
new_str[j]= toupper(input[i]);
i++;
j++;
}
else i++;
}
return new_str;
}
int main()
{
char str_1[100];
char str_2[100];
printf("Enter first word: ");
fgets(str_1, sizeof(str_1), stdin);
printf("Enter second word: ");
fgets(str_2, sizeof(str_2), stdin);
char *up_str_1 =(char *) malloc(strlen(str_1) + 1);
char *up_str_2 =(char *) malloc(strlen(str_2) + 1);
up_str_1= remove_up(str_1);
up_str_2= remove_up(str_2);
printf("%s", up_str_1);
printf("\n");
printf("%s", up_str_2);
return 0;
}
There are a few problems, but because this is tagged homework, I'll point them out but not give you the answer.
First of all, this doesn't do what you think:
int i, j = 0;
j will be initialized, but i probably won't start at 0. You need to initialize i to 0 as well.
Next, there's a typo - you missed a closing ] at (input[i<=122).
Finally, based on your answers to the questions, you probably aren't printing the result anyway: look up printf() or cout or whatever you prefer to use for outputting values.
It doesn't print results because you haven't used any print statements to show what comes back from your calls to remove_up.
To understand what is going on in your remove_up function, you need to understand this:
http://www.asciitable.com/
This code:
if (((input[i]) >= 65 && (input[i]<=90)) || ((input[i]>=97) && (input[i<=122)))
Is checking to see if a character is an alphabetic character in the ascii character set between these two ranges. Look at the link above. If it is in this set it's converting it to upper (redundant for half the data) and saving the result in your newly malloc'd string.
Problems:
1. You never set a null terminator in "new_str"
2. You never seem to free anything (though in this code it is trivial, in real code you could create problems, i.e. memory leaks).
3. "i" is redundant in the while loop. It's in both the if and else...
4. Rethink how you're using malloc (you probably don't want to use it this way in your custom functions unless you're going to cleanup after yourself)
There is probably more I'm missing, but that should help you see some problems.
Double check your use of parenths - you have more than needed. You are also missing a ']' in that if statement. Surprised it compiles.
change int i, j = 0; to int i = 0, j = 0;. Your i was initialized with a garbage value greater than strlen(input), and hence never entered the while loop.

Resources