char-Tables, Segmentation Error - c

I'm currently learning the C programming language, and I'm having some issues with it.
I'm getting Segmentation Error quite a lot when dealing with string (A.K.A char tables)
Here a simple algorithm just to delete the 'e' letter in the input string.
Example:
"hackers does exist" ->>> "hacks dos xist"
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
char T[200];
int j,i,l,times=0;
printf("Entre THE TXT\n");
gets(T);
while (T[i] != '\0')
{
l++;
i++;
}
for (i=0;i<l;i++)
{
if ( T[i] == 'e')
{
times++;
}
}
l=l-times;
i=0;
j=0;
while (i<l)
{
if ( T[j] != 'e')
{
T[i]=T[j];
i++;
j++;
}
else j++;
}
for (i=0;i<l;i++)
{
printf("%c",T[i]);
}
return 0;
}
Can you please tell me what I did wrong?
PS: I have noticed that each time I do incrementation as j++ in this code I will get the Segmentation Error... I really don't understand why.

Initialize i, j, l variables. Since uninitialized local variables are indeterminate. Reading them prior to assigning a value results in undefined behavior.
You are accessing the i and l variable without initialization.
while (T[i] != '\0')
{
l++;
i++;
}
Initialize as below.
int j = 0, i = 0, l = 0, times = 0;

As kiran Biradar already answered you only missed to initialize your integers.
You have several options here. I'll write them from most common to most discouraged.
Most used form, verbose but easier to maintain later.
int i = 0;
int j = 0;
int l = 0;
int times = 0;
Short form 1:
int i = 0, j = 0, l = 0, times 0;
Short form 2:
int i, j, l, times;
i = j = l = times = 0;
I'd suggest you also to use the features of at least the C99 Standard and reduce the scope of your variables completely. (Yes I know it's possible with {}-Blocks but I kinda like for-loops, if you iterate completely over something.
Hence my suggestion for your code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> // str(n)len
int main(void) // argv/argc is never used
{
char text[200];
printf("Entre THE TXT\n");
if (fgets(text, sizeof(text), stdin) == NULL) // fgets as gets is deprecated
exit(EXIT_FAILURE);
size_t len = strlen(text); // returns number of Characters excluding '\0'
if (len > 0 && text[len-1] == '\n') { // strip newline if present from fgets
text[len-1] = '\0';
}
unsigned int times = 0;
for (size_t i=0; i<len; i++) {
if (text[i] == 'e') {
times++;
}
}
// I'd prefer to use a `newlen` variable
len -= (size_t) times;
for (size_t j=0, i=0; i < len; j++) {
if (text[j] != 'e') {
text[i] = text[j];
i++;
}
}
text[len] = '\0'; // just for safety reasons terminate string properly
puts(text); // Use puts instead of calling printf several times.
return 0;
}
Further improvements:
Actually the times could be eliminated, as it's not really used to delete es.
So just remove the times block and all lines with it.

Related

Difference b/w using i<strlen() and str[i] != '\0'

When I use for(i=0;i<strlen(s);i++) then I am getting time limit exceed error. And When I use for(i=0;s[i]!='\0';i++) my code get successful submit. Why?
I am also providing link of question from codechef - https://www.codechef.com/problems/LCPESY
Type 1:
for (i = 0; i < strlen(s1); i++) {
f1[s1[i]]++;
}
for (i = 0; i < strlen(s2); i++) {
f2[s2[i]]++;
}
Type 2:
for (i = 0; s1[i] != '\0'; i++) {
f1[s1[i]]++;
}
for (i = 0; s2[i] != '\0'; i++) {
f2[s2[i]]++;
}
Complete code:
#include <stdio.h>
#include <string.h>
long int min(long int a, long int b) {
if (a >= b)
return b;
else
return a;
}
int main(void) {
// your code goes here
int t;
scanf("%d", &t);
while (t--) {
char s1[10001], s2[10001];
scanf("%s%s", s1, s2);
long int f1[200] = { 0 }, f2[200] = { 0 }, i, count = 0;
for (i = 0; i < strlen(s1); i++) {
f1[s1[i]]++;
}
for (i = 0; i < strlen(s2); i++) {
f2[s2[i]]++;
}
for (i = 0; i < 200; i++) {
count += min(f1[i], f2[i]);
}
printf("%ld\n", count);
}
return 0;
}
If a non-optimizing compiler is used it can be that strlen is re-evaluated once per each iteration. strlen then needs to check each and every character in the string for equivalence with 0. This results in quadratic runtime, where there are O(n²) checks for the terminatin null instead of just the necessary O(n) times. In the strlen code the timeout happens because it does perhaps 2,000,000 null checks and 10,000 other operations; the other code would do 2,000 null checks and those same 10,000 other operations and not time out.
However, this need not be a case. Due to the as-if rule, a C compiler can generate exactly equivalent machine for the cases
for (i = 0; i < strlen(s1); i++){
f1[s1[i]] ++;
}
and
for (i = 0; s1[i] != '\0'; i++) {
f1[s1[i]] ++;
}
because a compiler can easily prove that the inner loop cannot possibly change s1 and therefore both forms would behave equivalently.
In addition to #Antti Haapala good answer:`
Difference b/w using i<strlen() and str[i] != '\0'
Code like int i; ... i < strlen(s1) readily complains about mismatched sign-ness - when such warnings are enabled. Usually inoffensive code like that discourages wide use of that warning. I see that as a less preferred approach. str[i] != '\0' does not cause that warning.
Some other concerns
Prevent buffer overflow
char s1[10001], s2[10001];
// scanf("%s%s", s1, s2);
if (scanf("%10000s%10000s", s1, s2) == 2) {
// OK, success, lets go!
There are more than 200 characters.
// long int f1[200] = { 0 };
long int f1[256] = { 0 };
// or better
long int f1[UCHAR_MAX + 1] = { 0 };
Avoid a negative index
// f1[s1[i]]++;
f1[(unsigned char) s1[i]]++;
or use unquestionable unsigned types.
// char s1[10001];
unsigned char s1[10001];

Using Pointer Strings gives segmentation fault

The task was mainly to use pointers to input a string and slice it at places where there is a '\' character and output them in separate lines, using pointers. The program runs fine when I use arrays instead of pointers. However using pointers to store strings give the message "Segmentation fault". The code is as follows :
#include <stdio.h>
#include <stdlib.h>
int main() {
char *name;
char *sep[100];
int i = 0, j = 0, k = 0;
scanf("%[^\n]s", name);
for(i = 0; (*(name+i)) != '\0'; i++) {
if((*(name+i)) == '\\') {
*((*(sep+k))+j) = '\0';
j = 0;
k++;
} else {
*((*(sep+k))+j) = *(name+i);
j++;
}
}
for(i = 0; i <= k; i++) {
printf("%s\n", *(sep+i));
}
return 0;
}
It would be awesome if you could point out what and where the problem is, instead of giving me an alternative solution. TIA.
your pointers are null pointers.you are invoking undefined behavior by using them without assigning them to allocated memory.Allocate memory to them so that you can use them correctly and store words separated by \.Also,you can use [] instead of *.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char name[256];
char *sep[100];
for( int n = 0 ; n < 100 ; n++ )
{
sep[n] = malloc(30*sizeof(char));
}
int i = 0, j = 0, k = 0;
scanf(" %255[^\n]s", name);
for(i = 0; name[i] != '\0'; i++)
{
if( name[i] == '\\')
{
sep[k][j] = '\0';
j = 0;
k++;
}
else
{
sep[k][j] = name[i];
j++;
}
}
sep[k][j] = '\0';
for(i = 0; i <= k ; i++)
{
printf("%s\n",sep[i]);
}
for( int n = 0 ; n < 100 ; n++ )
{
free(sep[n]);
}
return 0;
}
In your code,
scanf("%[^\n]s", name);
name is an unintialized pointer. It does not point to any valid memory location. You need to allocate memory before you can use it.
The same goes out for sep array, too.
You can consider using an array for this purpose or see the man page of malloc() if you want to stick to a pointer.
FWIW, using an unitialized pointer can lead to undefined behavior.
You must allocate space for your pointers to avoid undefined behaviour: you cannot use a pointer without initializing it.
int main() {
char *name = malloc(MAX_DIM_OF_NAME+1);
char *sep[100];
for (int i=0; i<100; i++)
sep[i] = malloc(MAX_DIM_OF_NAME+1);
....
You call scanf with an uninitialized name.

Need String initialization advice

I got an assignment for wich i have to write an program that will take the letters in the first parameter string, and find them in the second parameter string like so:
./a.out "lolabab" "ablcocllcab"
the program needs to print "loab", because each letter should only be printed once.
here's the main part of my program
char *do_stuff(char *s1, char *s2)
{
int i, j, k;
char *out;
out = malloc(sizeof(char) * str_len(s1));
i = 0;
j = 0;
k = 0;
while (s2[j] != '\0' && s1[i] != '\0')
{
if (s2[j] == s1[i])
{
if (check_char(out, s1[i]) == 0)
{
out[k] = s1[i];
k++;
}
i++;
j = -1;
}
j++;
}
return (out);
}
my question is: if I dont initialize "out" i have a problem.
i initialize it with malloc at the moment, but i am not allowed to use malloc :).
any other way i tried, seems to not work for me (segmentation fault).
So how do i initialize a string without using malloc?
It's probably obvious, but i'm new at this so pls help. Thanks!
You can always pass the output buffer as a parameter
void do_stuff(char *s1, char *s2, char *out /* some large enough char [] */)
{
int i, j, k;
i = 0;
j = 0;
k = 0;
while (s2[j] != '\0' && s1[i] != '\0')
{
if (s2[j] == s1[i])
{
if (check_char(out, s1[i]) == 0)
{
out[k] = s1[i];
k++;
}
i++;
j = -1;
}
j++;
}
}
and in the calling function
char result[SOME_REASONABLE_SIZE] = {0} /* initialize it for the check_char function */;
do_stuff(argv[1], argv[2], result);
you should check that the function recieved the 2 arguments of course.
One more thing, try not to use strlen in the check char function, pass the current string length k to it, that way your program would be more efficient.
Use the fact that the number of characters is constant (and relatively small):
#include <limits.h>
#define CHAR_NUM (1<<CHAR_BIT)
#define FLAG(x) (1<<(x))
void get_common_chars(char* s1,char* s2,char out[CHAR_NUM])
{
int i,n;
int flags[CHAR_NUM] = {0};
for (i=0; s1[i]!=0; i++)
flags[(unsigned char)s1[i]] |= FLAG(1);
for (i=0; s2[i]!=0; i++)
flags[(unsigned char)s2[i]] |= FLAG(2);
n = 0;
for (i=0; i<CHAR_NUM; i++)
if (flags[i] == FLAG(1)|FLAG(2))
out[n++] = (char)i;
out[n] = 0;
}
If you're only interested in non-capital letters, then you can further improve it:
#define MIN_CHAR 'a'
#define MAX_CHAR 'z'
#define CHAR_NUM (MAX_CHAR-MIN_CHAR+1)
#define FLAG(x) (1<<(x))
void get_common_chars(char* s1,char* s2,char out[CHAR_NUM])
{
int i,n;
int flags[CHAR_NUM] = {0};
for (i=0; s1[i]!=0; i++)
if (MIN_CHAR <= s1[i] && s1[i] <= MAX_CHAR)
flags[s1[i]-MIN_CHAR] |= FLAG(1);
for (i=0; s2[i]!=0; i++)
if (MIN_CHAR <= s2[i] && s2[i] <= MAX_CHAR)
flags[s2[i]-MIN_CHAR] |= FLAG(1);
n = 0;
for (i=0; i<CHAR_NUM; i++)
if (flags[i] == FLAG(1)|FLAG(2))
out[n++] = (char)(MIN_CHAR+i);
out[n] = 0;
}
Here is a usage example:
#include <stdio.h>
int main(int argc,char* argv[])
{
char common_chars[CHAR_NUM];
if (argc >= 3)
{
get_common_chars(argv[1],argv[2],common_chars);
printf("%s\n",common_chars);
}
return 0;
}
If I understand correctly what you need, you should not create a new string, but use the command-line parameters, which are available in the arguments of main().
When you write
int main(int argc, char** argv) {
The compiler will arrange so that argc is the number of command-line arguments, and argv is an array of strings with the arguments. The first, argv[0], is the program name, and the rest are arguments passed to the program.
So this is one way to get your assignment done (high-level description only -- the rest is yours!)
Take the first argument, argv[1], and loop over it, character by character. For each character, try to find it in the other argument, argv[2]. If you find it, print the single character.
No need to allocate memory at all!
edit: if you don't want to print doubles, then one way would be to keep a static array that you could use as an index of already printed characters:
static int printed[26] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
When you print c, set its position to 1. And only print if the character's position is zero.
It's up to you to find out how to find the index of an arbitrary character (and to decide wether you want to differentiate between upper and lower case).

Table initialization fails with a variable

I need to make a console program that prints the following output :
aaaaaaaaa
abbbbbbba
abcccccba
abcdddcba
abcdedcba
abcdddcba
abcccccba
abbbbbbba
aaaaaaaaa
So I made the following code, wich seems to work :
#include <stdio.h>
#include <string.h>
int main()
{
int c, i = 0, p;
scanf("%d", &c);
int len = c*2-1;
printf("%d\n", len);
char ligne[9];
while (i < len-1){
p = 0;
for (int j = 0; j < c; j++){
ligne[len-1-j] = p+97;
ligne[j] = p+97;
if (j < c && p < i)
p++;
}
printf("%s\n", ligne);
i++;
}
return 0;
}
Which seems to work, but when I replace :
char ligne[9];
By :
char ligne[len];
I obtain the following output :
Your program output contains an invalid UTF8 character.
It seems that the table somehow "expanded" : there are much more than 9 fields in it.
I know that initializing tables with variables aren't allowed in some versions of C, but it ain't a problem for me. so, does anyone know where the prolem come from ?
Your problem is that you're trying to store 9 characters plus a terminal null into the space for 9 characters; this doesn't work.
Remove the - 1 from your calculation of len and ensure that the string is null terminated.
It was only by accident it worked with the fixed length array.
You could also fix the problem by revising the printf() statement to:
printf("%.9s\n", ligne);
or:
printf("%.*s\n", len, ligne);
This doesn't require a null-terminated string any more.
The code in the question prints the top half of the output, but gets stuck printing the same line over and over again on the bottom half of the output. This code fixes that, using the min() inline function to determine the maximum increment to be shown. It also validates the return value from scanf() to ensure that the value in c is reasonable (1..26) — failing silently if it is not OK.
#include <stdio.h>
#include <string.h>
static inline int min(int i, int j) { return (i < j) ? i : j; }
int main(void)
{
int c;
if (scanf("%d", &c) == 1 && c >= 1 && c <= 26)
{
int len = c*2-1;
printf("%d\n", len);
char ligne[len];
for (int i = 0; i < len; i++)
{
int p = 0;
int maxinc = min(len-1-i, i);
for (int j = 0; j < c; j++)
{
ligne[len-1-j] = p + 'a';
ligne[j] = p + 'a';
if (p < maxinc)
p++;
}
printf("%.*s\n", len, ligne);
}
}
return 0;
}
You have to allocate 1 char extra space and explicitely add a NULL terminator to the array ligne.
char ligne[len + 1];
ligne[len] = '\0';
char ligne[len+1];
for(int i=0;i<sizeof(ligne);++i)
ligne[i]=0;

Palindrome in C without pointers and recursion

I'm trying to determine if a phrase is a palindrome (a word that is the same from left to rigth) or not but i can't make it work. What's wrong?, i can't use pointers or recursion or string type variables
#include <stdio.h>
#include <string.h>
int main()
{
int i,j = 0,length;
char space = ' ';
char phrase [80],phrase2[80],phrase3[80];
printf("Give me the phrase: ");
gets(phrase);
length = strlen(phrase);
for(i =0; i <= length - 1; i++)
{
if(phrase[i] != space) //Makes the phrase without spaces
{
phrase2[i] = phrase[i];
j++;
}
}
for(i = length -1; i >= 0;i--)
{
if(phrase[i] != space) //Makes the phrase backwards an without spaces
{
phrase3[j] = phrase[i];
j++;
}
}
length = strlen(phrase2);
for(i =0; i <= length -1;i++) //Compare the phrases to know if they are the same
{
if(phrase2[i] != phrase3[i])
{
printf("It's not a palindrome\n");
return 0;
}
}
printf("It's a palindrome\n");
return 0;
}
Try this:
for(i =0, j=0; i <= length - 1; i++)
{
if(phrase[i] != space) //Makes the phrase without spaces
{
phrase2[j] = phrase[i];
j++;
}
}
for(i = length -1, j = 0; i >= 0;i--)
{
if(phrase[i] != space) //Makes the phrase backwards an without spaces
{
phrase3[j] = phrase[i];
j++;
}
}
length = j;
Update
In response to Praetorian's post here's the code to do it without copying the string.
#include <stdio.h>
#include <string.h>
int main()
{
int i, j, length;
char space = ' ';
char phrase[80];
printf("Give me the phrase: ");
gets(phrase);
length = strlen(phrase);
for( i = 0, j = length - 1; i < j; i++, j-- ) {
while (phrase[i] == space) i++;
while (phrase[j] == space) j--;
if( phrase[i] != phrase[j] ) {
printf("It's not a palindrome\n");
return 0;
}
}
printf("It's a palindrome\n");
return 0;
}
Before the 2nd loop you want to set j=0. It should work after that.
PS: If you debugged by printing out your three strings, you would've figured it out in a matter of minutes. When you don't know what goes wrong, print out the values of variables at intermediate steps, so you know where your problem occurs and what it is.
Your question has already been answered by others but I'm posting this code to show that it is not necessary to make the phrase3 copy to hold the reversed string.
#include <stdio.h>
#include <string.h>
int main()
{
int i, j, length, halfLength;
char space = ' ';
char phrase1[80], phrase2[80];
printf("Give me the phrase: ");
gets(phrase1);
length = strlen(phrase1);
for( i = 0, j = 0; i <= length; ++i ) {
if( phrase1[i] != space ) { //Makes the phrase1 without spaces
phrase2[j++] = phrase1[i];
}
}
length = strlen(phrase2);
halfLength = length / 2;
for( i = 0, j = length - 1; i < halfLength; ++i, --j ) {
if( phrase2[i] != phrase2[j] ) {
printf("It's not a palindrome\n");
return 0;
}
}
printf("It's a palindrome\n");
return 0;
}
This is what I came up with:
#include <stdio.h>
void main() {
char a[50],b[50];
int i=0,j,ele,test=0,x;
while((a[i]=getchar())!='\n') {
if(a[i]!=' ' && a[i]!=',') //do not read whitespaces and commas(for palindromes like "Ah, Satan sees Natasha")
i++;
}
a[i]='\0';
ele=strlen(a);
// Convert string to lower case (like reverse of Ava is avA and they're not equal)
for(i=0; i<ele; i++)
if(a[i]>='A'&&a[i]<='Z')
a[i] = a[i]+('a'-'A');
x = ele-1;
for(j=0; j<ele; j++) {
b[j] = a[x];
x--;
}
for(i=0; i<ele; i++)
if(a[i]==b[i])
test++;
if(test==ele)
printf("You entered a palindrome!");
else
printf("That's not a palindrome!");
}
Probably not the best way for palindromes, but I'm proud I made this on my own took me 1 hour :( lol
Why not use a std::stack? You will need two loops, each iterating the length of the input string. In the first loop, go through the input string once, pushing each character ont the stack. In the second loop, pop a character off the stack and compare it with the character at the index. If you get a mismatch before the loop ends, you don't have a palindrome. The nice thing with this is that you don't have to worry about the even/odd length corner-case. It will just work.
(If you are so inclined, you can use one stack (LIFO) and one queue (FIFO) but that doesn't substantially change the algorithm).
Here's the implementation:
bool palindrome(const char *s)
{
std::stack<char> p; // be sure to #include <stack>
for(int i = 0; s[i] != 0; i++)
p.push(s[i]);
for(int i = 0; s[i] != 0; i++)
{
if(p.top() != s[i])
return false; // not a palindrome!
p.pop();
}
return true;
}
Skipping spaces is left as an exercise to the reader ;)

Resources