Search code examples
cubuntuprintfstring-formatting

printf not printing a variable in ubuntu (C)


I have a problem with printing string from a variable using 'printf' and '%s' in c. when I am compiling the code below and running the exe file in windows using the '<' oparand to enter values from a text file as the input, the string will be printed fine and you could see it on the cmd, but when I am compiling and running the elf file in ubunto and using the '<' oparand as well the string from the variable won't be printed and only the characters that are after the '%s' will be printed to the terminal.

Note that when using puts to print only the string from the variable it works in both ubuntu and windows, why does is heppening?.

also when I am entering input directly from the keyboard the 'printf' works fine as well in ubuntu.

Can someone explain to me why does printf does't work when getting input from a file and if there is a way to format a string in ubuntu? Thanks for you time.


here is a picture of the cmd to show that it works fine on windows: enter image description here

here is a picture of the ubuntu terminal to show the problem: enter image description here

as you can see the variable and what comes before it does not get printed.

(the problem is in line 101 inside the 'initialze_names' function) in this segment of code:

if (!is_name_unique(i, names[i]))
{
    printf("The name '%s' is already exists in the array. Please Enter only uniqe names", names[i]);
    return 0;
}

I am compiling the code using this Makefile for ubuntu:

CFLAGS = -Wall -ansi -pedantic

all: get_name

get_name: get_name.o
    gcc $(CFLAGS) get_name.o -o get_name
    rm get_name.o

get_name.o: get_name.c
    gcc $(CFLAGS) -c get_name.c

and this command for windows:

gcc -Wall -ansi -pedantic -o get_name.exe get_name.c

for those who are intrested in the complete code.

/*
* The program will let the user enter 30 uniuqe names and will call a function to get randomly a string from the array.
* it will do it using the 'initialze_names' function to get the names and validate them, 'get_name' to get a random name from the array
* and 'is_name_unique' to check if the name is uniuqe.
*
* this goal is achived by fisrt using initialze_names to get the user input and remove the new line character '\n'.
* after that it will check if the string is uniuqe using the is_name_uniuqe function and.
* then it wil print the array as it is and call get_name ten times and print the random name gotten each iteration.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>

#define MAX_NAMES 30
#define MAX_LENGTH 21
#define NUMBER_OF_NAMES_TO_RANDOMIZE 10

char names[MAX_NAMES][MAX_LENGTH] = { 0 };

/* signature for the functions used in the code so the compiler will identify the functions regardless to where they are implemented */
int initialze_names();
char* get_name();
int is_name_unique(int count, char newName[MAX_LENGTH]);
void print_array();
int comapre_strings(char str1[MAX_LENGTH], char str2[MAX_LENGTH]);

int main()
{
    int i = 0;
    char* random_name = NULL;

    /* Use current time as seed for random generator */
    srand((unsigned int)time(0));

    /* Calling initialze_names to get the user 30 uniqe names as input. */
    printf("Please feed the system with 30 uniqe names:\n");
    if (!initialze_names())
    {
        /* exiting the program if somthing went wrong in the inizialzation */
        return 0;
    }

    /* printing the names array to visualze the names incase the input got from a file. */
    print_array();

    printf("%d randomize names from the input:\n", MAX_NAMES);
    /* iterating 10 times and calling get_name each time to get random name from the array */
    for (i = 0; i < NUMBER_OF_NAMES_TO_RANDOMIZE; i++)
    {
        random_name = get_name();
        /* checking if the random name is returned */
        if (random_name != NULL)
        {
            /* printing the name if exists */
            puts(random_name);
        }
    }

    return 0;
}

/*
* initialze_names function looping from 0 to MAX_NAMES and letting the user enter an input representing a name to each cell in the names array
* then function will also be removing '\n' character if needed, clean the buffer in cases of overflow and for each name checking if it is unique.
*
* retrun: (int) - 0 if something went wrong in the proccess of getting the input and 1 if the the initialzation completed succesfuly.
*/
int initialze_names()
{
    int i = 0;
    char c = ' ';
    int length = 0;

    for (i = 0; i < MAX_NAMES; i++)
    {
        /* getting the user input and assaigning it to the array at index i */
        if (fgets(names[i], sizeof(names[i]), stdin) == NULL)
        {
            perror("Error reading input");
            return 0;
        }

        /* getting the name length */
        length = strlen(names[i]);
        if (length > 0 && names[i][length - 1] == '\n')
        {
            /* removing new line character '\n' if exists */
            names[i][length - 1] = '\0';
        }
        else
        {
            /* if string is to long, cleaning the buffer so the input won't overflow to next iteration. */
            while ((c = getchar()) != '\n' && c != EOF);
        }
        
        /* calling is_name_unique to check if the name already exists in the array */
        
        if (!is_name_unique(i, names[i]))
        {
            printf("The name '%s' is already exists in the array. Please Enter only uniqe names", names[i]);
            return 0;
        }
        
    }
    return 1;
}

/*
* get_name function generating randomize index from 0 to 30 and uses it to get a random name from the list
*
* return: (char*) name[i] - a pointer to characters array containing the chosen name from the array
*/
char* get_name()
{
    /* randomizing the index */
    int i = rand() % MAX_NAMES;
    if (i > 0 && i < MAX_NAMES)
    {
        return names[i];
    }
    return NULL;
}

/*
* is_name_unique getting the count and a new name check if it already exists in the array.
*
* input: (int) count - the index representing the last element position being inserted to the array.
* input: (char*) newName - the new name that the user inserted.
*
* return: (int) - 0 if the name already exists in the array and 1 if it does not.
*/
int is_name_unique(int count, char newName[MAX_LENGTH])
{
    int i = 0;

    /* iterating from 0 up to the count - 1 to check if the same name comes anywhere before it in the array */
    for (i = 0; i < count; i++)
    {
        /* comparing the strings without case sensetivity. */
        if (comapre_strings(names[i], newName) == 0)
        {   
            return 0;
        }
    }
    return 1;
}

/*
* print_array iterating over the names array and printing each name and his index.
*/
void print_array()
{
    int i = 0;

    printf("\nThe names gotten from user:\n");
    for (i = 0; i < MAX_NAMES; i++)
    {
        printf("%d. %s ", i + 1, names[i]);
    }
    printf("\n\n");
}

/*
* compare_strings is a function that gets two strings converting each string to lower case and returns 0 if they are equal to each other.
*
* input: (char*) str1 - the first string
* input: (char*) str2 - the second string
*
* retrun: (int) - 0 if equal 1 if str1 grater then str2 and -1 if str1 smaller then str2
*/
int comapre_strings(char str1[MAX_LENGTH], char str2[MAX_LENGTH])
{
    int i = 0;

    /* iterating over str1 and converting him to lowercase */
    for (i = 0; i < strlen(str1); i++)
    {
        str1[i] = tolower(str1[i]);
    }

    /* iterating over str2 and converting him to lowercase */
    for (i = 0; i < strlen(str2); i++)
    {
        str2[i] = tolower(str2[i]);
    }
    
    /* comparing between the two and returning the result */
    return strcmp(str1, str2);
}

Solution

  • The text file you are using as input was made while you were running Windows and each line is terminated with CR+LF (\r and \n).

    When read under Ubuntu, CR is kept and is displayed by printf(). Displaying a CR character makes the following text being displayed at the beginning of the line (CR = carriage return).

    Solution: use the dos2unix utility to convert your input file by changing the CR+LF line endings to LF.