Table initialization fails with a variable - c

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;

Related

How do I compare an integer with a character in a string in C?

I want to compare the integers in a string with integers (0-9) and I wrote this -
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char num[100];
int count = 0;
scanf("%s", num);
int len = strlen(num);
for (int i = 0; i <= 9; i++)
{
for (int j = 0; j <= len; j++)
{
if (i == (num[j] - '0'))
{
count++;
}
}
printf("%d ", count);
count = 0;
}
return 0;
}
No problems with this (works in most cases but it is failing in few cases). So can you please give me alternate and best idea to do this?
Thanks in advance
Complete pic -
The root cause is not in char comparison, but in the under-allocated buffer:
char num[100];
The assignment constraint is:
1 <= len(num) <= 1000
After increasing the buffer size, all the tests pass.
Besides a too small input buffer (i.e. 100 instead of 1001), I think your approach is too complex.
Instead of a nested loop, I'll suggest an array to count the frequency, i.e. an array with 10 elements so that you have a counter for each digit.
int main() {
char num[1001]; // 1000 chars + 1 zero termination
int count[10] = {0}; // Array of 10 zero initialized counters, one for each digit
scanf("%1000s", num); // At max accept 1000 chars input
char* p = num;
while (*p)
{
if (isdigit(*p) ++count[*p - '0'];
++p;
}
for (int i = 0; i < 10; ++i) printf("%d ", count[i]);
puts("");
return 0;
}
If you don't want to use isdigit you can instead do:
if (*p >= '0' && *p <= '9') ++count[*p - '0'];

printing a string in a specific format

So I created have a program that basically prints any given string like that:
Example:
Input:
Hello
Output:
Hello
ello
llo
lo
o
The problem is that for some reason if I use icdiff and compare my output with that output in a text file it says that I am missing elements and that I have more spaces than it should.
Icdiff output:
Hello
ello
llo
As you can see this is clearly different than what I have, but if I test it on the terminal I get the expected output.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_array(char *p, int tamanho) {
int i;
for (i = 0; i < tamanho; i++) {
printf("%c", p[i]);
}
printf("\n");
}
void nova_str(char *p, char *s, int inicio, int tamanho) {
int i;
for (i = inicio; i < tamanho; i++) {
s[i] = p[i];
}
}
int main() {
char p[1001];
int len;
int j;
scanf("%s", p);
len = strlen(p);
print_array(p, len);
for (j = 1; j < len; j++) {
char *np = (char *)calloc(len + 1, sizeof(char));
nova_str(p, np, j, len);
print_array(np, len);
free(np);
}
return 0;
}
Really any help would be appreciated.
The problem is in the nova_str function: you use the same index into the source and the destination, so the destination array still starts with initcio null bytes which are printed by the print_array and appear as spaces on your system. The array is initialized to all bits zero by calloc().
Here is a much simpler version:
#include <stdio.h>
int main() {
char p[1001];
if (scanf("%1000s", p) == 1) {
for (int i = 0; p[i] != '\0'; i++) {
/* print the word starting at offset i */
printf("%s\n", p + i);
}
}
return 0;
}
calloc() is setting the memory to zero, so you are printing null characters in print_array() when it should be spaces. Replace those null characters with spaces there and this is solved, although I think there is an easier way to achieve what you are trying to do.
If you don't want the letters to be prepended by spaces, add an if (p[i] == '\0') continue; before printf() in print_array() instead.

How to get the length of the relevant palindrome of a word in a string?

I need to get the length of the palindrome of the word in a string. Ex. tomyot length =2.
I wrote the following code but it doesn't work.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char str[20] = "tomyot";
char rstr[20];
strcpy(rstr, str);
strrev(rstr);
int i,j;
int count = 0;
int s=0;
for(i=0;i<strlen(str); i++){
for(j=s;j<strlen(str); j++){
if(str[i] == rstr[j]){
count+=1;
s = j+1;
continue;
}
}
}
printf("%d",count);
return 0;
}
Replace
sizeof(str)
with
strlen(str)
The former one returns the size of the str array which is 20 and the latter one returns the length of the contents of str which is 6.
I have made the changes and put comments in the code in /* .. */ blocks:
#include <stdio.h>
#include <string.h>
int main(void) {
/*
- You don't need to compute the reverse of the string, the input string itself will do your work.
- strrev() is not supported in GCC, so don't use it. See https://stackoverflow.com/a/8534275/4688321
for alternative implementation
*/
char str[20] = "tomyot";
int len_str = strlen(str);
int i, j, cnt = 0;
/*
- You don't need two nested for loops, one loop with two pointers:
first from the start of string and other from end of the string will do
- Just compare the ith character (from start) with the jth character (from end)
- Stop wherever i and j cross each other i.e. when i > j
*/
for (i = 0, j = len_str - 1; i <= j && i < len_str - 1; i++, j--) {
if (str[i] == str[j]) {
cnt++;
}
else break;
}
printf("%d\n", cnt);
return 0;
}

Copying argv and checking it for a palindrome

I'm writing a program to check for palindromes. I recently picked up C and was wondering is there a reason why my take on it won't work? Does it have something to do with my use of directly copying argv into a char array
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc,char *argv[]){
int i;
int a;
int size;
for(a = 1; a < argc; a++){
char *reverseThis = argv[a];
char *normal = argv[a];
size = strlen(reverseThis);
for(i = 0; i < size; i++){
reverseThis[i] = normal[size - i - 1];
}
for(i = 0; i < size; i++){
reverseThis[i] = tolower(reverseThis[i]);
normal[i] = tolower(normal[i]);
}
if(strcmp(reverseThis,normal)==0){
printf("\"%s\": on palindromi\n",argv[i]);
}
else
printf("\"%s\": ei ole palindromi\n",argv[i]);
}
return 0;
}
In your code you are not copying the strings, you assigned both normal and reverseThis to same string argv[a].In reverseThis you need to copy argv[a] after allocating memory.
Just modify your code in forloop:
for(a = 1; a < argc; a++){
char *normal = argv[a];
size = strlen(normal);
char *reverseThis = (char*)malloc((size+1)*sizeof(char));
int j=0;
for(i = size-1; i >= 0; i++){
reverseThis[j++] = normal[i];
}
reverseThis[j]='\0';
.
.
You are using an incorrect approach.
For starters this loop
for(i = 0; i < size; i++){
reverseThis[i] = normal[size - i - 1];
}
copies the right half of the string in reverse order in the left half of the string totally overwriting its left part.
For example if you have a string like this "123456" then after the loop it will look like "654456"
This comparison also does not make sense
if(strcmp(reverseThis,normal)==0){
because the both pointers point to the same string. So the condition always yields true.
Take into account that these declarations
char *reverseThis = argv[a];
char *normal = argv[a];
do not copy the original string pointed to by argv[a]. The declared pointers just point to the first character of the same string.
And here is a typo
printf("\"%s\": on palindromi\n",argv[i]);
^^^
The task can be done simpler without changing the strings.
For example
size_t n = strlen( argv[a] );
size_t i = 0;
while ( i < n / 2 && tolower( ( unsigned char )argv[i] ) == tolower( ( unsigned char )argv[n -i - 1] ) ) ++i;
if ( i == n / 2 )
{
printf("\"%s\": on palindromi\n", argv[a]);
}
else
{
printf("\"%s\": ei ole palindromi\n",argv[a]);
}
If you indeed need to copy the strings then either declare variable length arrays (if the compiler supports them) or allocate arrays dynamically. For example (declaring variable length arrays):
size = strlen( argv[a] );
char reverseThis[size + 1];
char normal[size + 1];
strcpy( reverseThis, argv[a] );
strcpy( normal, argv[a] );
You don't need to reverse the string and compare to find out whether the input string is palindrome or not.
You can simply compare the characters of the string starting from both ends of the string and move one character forward from the start of the string and one character backward from the end of the string. If all character matches till you reach to mid of string then the string is palindrome otherwise not a palindrome.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc,char *argv[]){
int i, a, size;
for(a = 1; a < argc; a++){
char *ptr= argv[a];
int notpalindrom = 0;
size = strlen(ptr) - 1;
for(i = 0; i < size; ){
if (tolower(ptr[i++]) != tolower(ptr[size--])){
notpalindrom = 1;
break;
}
}
if (notpalindrom)
printf ("%s is not palindrom\n", ptr);
else
printf ("%s is palindrom\n", ptr);
}
return 0;
}
The first "if" take from argv in index "i", i == to the last change that has changed in the last "for", in your case i == 4, and the program crashed cause their isn't string in that member, to fix that you should change the "i" to 0 before the "if".

Something is wrong with this C code to reverse string, but I dont know what ? please help

I am beginnner to programming. I wrote this little program to reverse a string. But if I try to reverse a string which is less than 5 characters long then it gives wrong output. I cant seem to find whats wrong.
#include<stdio.h>
#include<string.h>
int main()
{
char test[50];
char rtest[50];
int i, j=0;
printf("Enter string : ");
scanf("%s", test);
int max = strlen(test) - 1;
for ( i = max; i>=0; i--)
{
rtest[j] = test[i];
j++;
}
printf("Reversal is : %s\n", rtest);
return 0;
}
You are not terminating the reversed string with a 0. (all strings in C are 0-terminated)
In this case, the printf will (likely, depending on the unitialized contents of the rtest array) create a buffer overflow.
Add a rtest[max+1]=0; after the for loop and everything should be fine.
Otherwise you can declare char rtest[50] = {0} (this will initialize the whole array with 0s).
rtest is unitialized.
You should add rtest[j] = '\0'; after the for loop to say where the string ends
void reverse(char* str)
{
int len = strlen(str);
for (int i = 0; i < len / 2; ++i) {
char tmp = str[i];
str[i] = str[len - 1 - i];
str[len - 1 - i] = tmp;
}
}

Resources