Need String initialization advice - c

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).

Related

In c, when I use %s to print out the contents of a char array it prints blank, but when I loop over it and print each character it works

Just implementing a simple sorting algorithm to sort a string. I tried printing out the buff char array with printf("%s\n") but it came out blank. The contents of the array are there, though, and I checked with printing out each character of it. What am I missing here?
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
if (argc != 2)
{
printf("usage: ./sortstring string");
exit(1);
}
int size = 1; // 1 to account for '\0'
for (int i = 0; argv[1][i] != '\0'; i++)
{
size += 1;
}
char buff[size];
strcpy(buff, argv[1]);
char temp;
for (int i = 0; i < size; i++)
{
for (int j = i + 1; j < size; j++)
{
if (tolower(buff[i]) > tolower(buff[j]))
{
temp = buff[i];
buff[i] = buff[j];
buff[j] = temp;
}
}
}
// printf("%s\n", buff);
for (int i = 0; i < size; i++)
{
printf("%c", buff[i]);
}
return 0;
}
Change "%c" to "%d" in printf and see the result.
for (int i = 0; i < size; i++)
{
printf("%d", buff[i]);
}
strcpy copies terminating null byte with the source string.
You sorted terminating null byte with other characters.
Your sorting function is probably sorting the null character to position 0.
Instead of attempting to manually count characters in "argc[1]", you could just use the "strlen" function. So, instead of
int size = 1; // 1 to account for '\0'
for (int i = 0; argv[1][i] != '\0'; i++)
{
size += 1;
}
You could use
int size = strlen(argv[1]);
Regards.
The problem is that you're initializing size with 1. I know you did that because you need one more char to \0, but after that, either you need to loop through size - 1 or you can decrease the value of size before your for loops.
Another thing you can do is: initialize size with 0, and use size + 1 while creating your array.

Create function which copy all values from one char array to another char array in C (segmentation fault)

I have a task. I must copy all values form one char array (sentence[]) to another empty char array sentence2[]), but I don't know why I get segmentation fault. They told us also that we must create own strlen function to check how long is string.
This is my code
#include <stdio.h>
#include <stdlib.h>
int new_strlen (char *tab)
{
int i;
for (i = 0; tab[i] != '\0'; ++i);
return i;
}
int copyText(char from[],char to[],int max)
{
int i, j;
if (new_strlen(from) <= max)
{
for(int i = 0; i != '\0'; i++) {
to[i] = from[i];
}
to[i+1] = '\0';
}
return 0;
}
int main (int argc, char *argv[])
{
char sentence[] = "C is \n a \n programming \t language";
char sentence2[1000];
copyText(sentence, sentence2, 1000);
printf("Show my array: %s \n", sentence2);
return 0;
}
Here are the bugs:
int copyText(char from[],char to[],int max)
{
int i, j; // minor problem: j is useless
if (new_strlen(from) <= max) // should be < instead of <=
{
for(int i = 0; i != '\0'; i++) { // here you declare a new i variable
// unrelated to the i declared at the beginning
to[i] = from[i];
}
to[i+1] = '\0'; // here you use again the i declared at the beginning
// which hasn't been initialized
// and i already is the index of the terminator
// therefore it should be to[i]
}
return 0;
}
This line contains two errors:
for(int i = 0; i != '\0'; i++)
i != '\0' is equivalent to i != 0. Now youv'e probably realized your error. Actually you need to test if from[i] is 0.
to[i+1] = '\0' : here i has already been incremented by the for loop, i already contains the index of the \0 terminator, therefore it should be to[i] = '\0'
And finally in this line you use the i variable declard at the beginning o the function whose content is indeterminate as you have never assigned anything to it and it is most likely this line that causes the segmentation fault: to[i+1] = '\0';
Finally there is another problem that will cause problems if the length of the string is max:
if (new_strlen(from) <= max) // should be < instead of <=
If the length of the string is max, then \0 will be put one beyond the end of the buffer, hence a buffer overflow.
You want this:
int copyText(char from[],char to[],int max)
{
if (new_strlen(from) < max)
{
int i;
for(i = 0; from[i] != '\0'; i++)
to[i] = from[i];
}
to[i] = '\0';
}
return 0;
}
Three issues with copyText
i != '\0' should be from[i] != '\0'
int i = 0 should be just i = 0 in for loop to not shadow the other i and also pointless to do it.
to[i+1] should be just to[i]
I modify my program like you said.
My program
#include <stdio.h>
#include <stdlib.h>
int new_strlen (char *tab)
{
int i;
for (i = 0; tab[i] != '\0'; ++i);
return i;
}
int copyText(char from[],char to[],int max)
{
if (new_strlen(from) < max)
{
int i;
for(int i = 0; from[i] != '\0'; i++)
{
to[i] = from[i];
}
to[i] = '\0';
}
return 0;
}
int main (int argc, char *argv[])
{
char sentence[] = "C is \n a \n programming \t language";
char sentence2[30];
copyText(sentence, sentence2, 30);
printf("Show my array: %s \n", sentence2);
return 0;
}
The output
Show my array: h�ܙ�
Why my output is wrong?
I sloved your problem. You just missed 'form[i]' in for loop of copytext() funtion. And used (new_strlen(from) <= max) instead (new_strlen(from) < max). And removed to[i+1] = '\0'; which was not needed.
#include <stdio.h>
#include <stdlib.h>
int new_strlen (char *tab)
{
int i;
for (i = 0; tab[i] != '\0'; ++i);
return i;
}
int copyText(char from[],char to[],int max)
{
if (new_strlen(from) <= max)
{
for(int i = 0; from[i] != '\0'; i++)
{
to[i] = from[i];
}
}
return 0;
}
int main (int argc, char *argv[])
{
char sentence[] = "C is \n a \n programming \t language";
char sentence2[1000];
copyText(sentence, sentence2, 1000);
printf("Show my array: %s \n", sentence2);
return 0;
}
I have a task. I must copy all values form one char array
(sentence[]) to another empty char array sentence2[]),
I you must copy all values then the third parameter of the function copyText
int copyText(char from[],char to[],int max);
is redundant. In general it does allow to copy all values.
I think that by "all values" you mean all characters of a string stored in the source array.
To copy a string from one character array to another character array the function that calculates the length of the string is not required. It is also redundant.
The return type int of the function copyText does not make a sense. The character array from which the stored string is copied shall have the qualifier const.
Standard C string functions follow the convention that the destination character array should be the first function parameter and functions should return pointer to the destination character array.
Within the function the declared variable j is not used
int i, j;
The reason of the segmentation fault is that you are using the non-initialized variable i to set the terminating zero character in the destination array. That is you declared an uninitialized variable i
int i, j;
then in the if statement in its inner loop
if (new_strlen(from) <= max)
{
for(int i = 0; i != '\0'; i++) {
^^^^^^^^^
to[i] = from[i];
}
to[i+1] = '\0';
}
you declared one more variable i which will not be alive outside the loop. The loop itself iterates never because the condition of the loop
i != '\0'
is not satisfied. The variable i was initialized by 0 and is compared with the same 0 that is written as an octal character literal.
So in this statement
to[i+1] = '\0';
there is used the initialized variable i declared in the beginning of the function before the if statement.
I am sure what you are required to write is an analog of ths atndard C function strcpy.
In this case the program can look the following way
#include <stdio.h>
char * copyText( char to[], const char from[] )
{
for ( char *p = to; ( *p++ = *from++ ) != 0; ) { /* empty */ }
return to;
}
int main (void)
{
enum { N = 1000 };
char sentence[] = "C is \n a \n programming \t language";
char sentence2[N];
printf("Show my array: %s \n", copyText(sentence2, sentence ) );
return 0;
}
The program output is
Show my array: C is
a
programming language

How to reassign a string?

I am trying to write a program which merges a lines from stdin and print only those sentences which are longer than 80 characters. The first found line works well - the later ones, however, are empty. I think that I am doing something wrong with the line
current_sentence = malloc(sentence_len);.
How can I reassign a string correctly?
Code
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# define BUFFERSIZE 100
char* merge_string(char *text[], int n){
int i;
char *result = malloc(BUFFERSIZE * n);
for (i=0; i < n; i++){
strcat(result, text[i]);
}
return result;
}
int main(int argc, char *argv[]){
char buffer[BUFFERSIZE];
int i = 0;
char *text[BUFFERSIZE];
while(fgets(buffer, BUFFERSIZE, stdin) != NULL){
text[i] = strdup(buffer);
i++;
}
char *sentence = merge_string(text, i);
int sentence_len = strlen(sentence);
int j = 0;
int counter = 0;
char *current_sentence = malloc(sentence_len);
while (j < sentence_len){
current_sentence[counter] = sentence[j];
if (sentence[j] == '\n' && counter >= 80){
printf(":::HIT:::%s\n\n\n", current_sentence);
counter = 0;
current_sentence = malloc(sentence_len);
}
else if (sentence[j] == '\n'){
puts("Resetting counter");
counter = 0;
}
j++; counter++;
}
return 0;
}
Output
make 1_17; ./1_17 < example.txt
make: `1_17' is up to date.
Resetting counter
Resetting counter
:::HIT:::SHenri Cartier-Bresson (1908-2004) said "Your first 10,000 photographs are your worst," but he shot more than one an hour.)
Resetting counter
:::HIT:::
Resetting counter
:::HIT:::
You are not terminating current_sentence with a null character ('\0'). If you want printf to print the string properly, better make sure it is null-terminated.
By the way, there's no need for a second malloc. Reuse the memory allocated for current_sentence without re-allocating.
Also note that you're not freeing the allocated memory properly. You should be use a matching free call for each malloc. Perhaps this isn't a problem now, but it creates a memory leak.
Your loop should look something like this:
while (j < sentence_len)
{
current_sentence[counter] = sentence[j];
if (sentence[j] == '\n')
{
if (counter >= 80)
{
current_sentence[counter + 1] = '\0'; // Make string null-terminated
printf(":::HIT:::%s\n\n\n", current_sentence);
}
else
{
puts("Resetting counter");
}
counter = 0;
}
else
{
counter++;
}
j++;
}
free(current_sentence); // Free allocated memory
Then again, as mentioned in a comment, you'd rather let fgets do the work for you indeed.
char *text[BUFFERSIZE];
should be
char text[BUFFERSIZE];

Return Array of Strings with String Input

I'm trying to take a string and break it into "word" components and store that in an array of strings.
"Hello my name is Bill." should give back a char** with elements, "Hello", "my", "name", "is", and "Bill."
My code will compile however I keep encountering a runtime error (I don't get warnings anymore and my debugger gdb doesn't work)>
I'm running on minGW on Window 8.
#include <stdio.h>
#include <stdlib.h>
char** words(char* string)
{
int i = 0;
int j = 0;
int k =0;
int count = 0;
char** stringArray = (char**) malloc(sizeof(char)*30*30);
while( string[i] != '\0' )
{
if(string[i] != ' ')
{
j =0;
while(string[i+j+1] != ' ')
{
j++;
}
i = i+j;
for(k=0; k<=j; k++)
{
stringArray[count][k] = string[i+k];
}
count++;
}
i++;
}
return stringArray;
}
int main()
{
char message[20] = "abcd efgh ijkl mno";
char** wordArray = words(message);
printf("%c\n\n", wordArray[0][0]);
int i =0;
while(wordArray[i])
{
printf("%s\n", wordArray[i]);
i++;
}
printf("\nThe problem is not with the words function");
return 0;
}
There are couple of issues that have been mentioned in the comments.
The allocation should look something like:
#include <ctype.h> // for isspace()
#define MAXSTRLEN 30 // using a symbolic constant
char **stringArray;
int i, j, k;
stringArray = malloc(sizeof(char*) * MAXSTRLEN); // don't cast from malloc
for (i = 0; i < 30; ++i) {
stringArray[i] = malloc(sizeof(char) * MAXSTRLEN);
}
// TODO error checking: malloc could return NULL
while copying the substrings would look like:
i = 0;
j = 0;
while( string[i] != '\0') // go through the whole string
{
while (string[i] != '\0' && isspace(string[i])) {
i++; // skip whitespaces
}
k = 0;
while (string[i] != '\0' && !isspace(string[i])) { // copy word until whitepace or end of string
stringArray[j][k++] = string[i++];
}
stringArray[j][k] = '\0'; // EOS !!!
j++;
}
and printing (j is number of words actually read):
for (i = 0; i < j/*30*/; ++i) { // (!) how to print
printf("%s\n", stringArray[i]);
}
And, yes strtok would also do the job.
In words() you're assigning values to stringArray as a two-dimensional array, and in main() you're reading values from it as an array of pointers. Those are not the same thing.
So you need to change it so that you're consistently treating it as a 2D array, or so that you're consistently treating it as an array of pointers (char* to be exact). Either will work... see the comments above for elaboration.
This code is all wrong.
char** stringArray = (char**) malloc(sizeof(char)*30*30);
First of all, sizeof(char) is always one, second, you don't need to cast a void. So:
char **stringArray = malloc(30 * 30);
But that doesn't make any sense because it's an array of char *, so you should allocate in terms of that:
char **stringArray = malloc(sizeof(char *) * 30);
Or even better:
char **stringArray = malloc(sizeof(*stringArray) * 30);
So now you have an array with 30 char *, but each of those is not initialized, so you need to do that:
for (i = 0; i < 30; i++)
stringArray[i] = malloc(sizeof(**stringArray) * 30);
If you don't do that, you can't access stringArray[count][k].
And then you assume the last element in the array is NULL, but you never set it, so you either do stringArray[count] = NULL at the end of words(), or you do calloc() instead of malloc().
I'm not analyzing the code beyond that; it's just all wrong.

Splitting strings in C and saving it inside an array of strings, but results as garbage

Been searching through here but please forgive me if this post is a duplicate...
I just want to clarify things wherein I am not sure of...
First of all, let me give an introduction to what I have in mind:
The user will be asked to input a command (similar to the command line/shell commands).
The command will be received/inputted as a string separated by white spaces.
Next the string will be tokenized (split), the number of words will be counted.
With that number of words at hand, I will have to create a dynamic multi-dimensional array of strings, where the size/number of strings are the number of words we counted.
Example:
I Name 1234123 123123
The number of words/strings inside that command is 4, so the number of string pointers will be dynamically allocated.
I want this strings to be stored in a dynamic multi-dimensional array where:
char ** arguments;
int count;
I want to access the values inside the arguments array as:
for(i = 0; i < count; i++)
printf("%s", arguments[i]);
MY PROBLEM IS
When I try to access these variables in my main function, the values inside the arguments variable are garbage and the count variable continues to increment, knowing that I have initialized the count variable back to 0.
You can check on my code if I have done something vague or wrong.
Thanks!
Here are the codes that I was able to create where in which I think are useful:
/* This function counts the number of words inside the command input. */
int word_count(char * str)
{
int i, ctr;
for(ctr = i = 0; str[i] != '\0'; i++)
{
while(isspace(str[i]))
i++;
if(str[i] != '\0')
{
ctr++;
while(str[i] != '\0' && ! isspace(str[i]))
i++;
}
}
return ctr;
}
/* This function splits the strings inside the command. */
void split_command(int count, char *** argv, char * command)
{
char buffer[31];
int i, j, k;
*argv = (char **) malloc(sizeof(char *) * count);
for(i = k = 0; command[i] != '\0'; i++)
{
while(isspace(command[i]))
i++;
if(command[i] != '\0')
{
for(j = 0 ;j < 30 && command[i] != '\0' && ! isspace(command[i]); j++, i++)
buffer[j] = (j != 0) ? command[i] : toupper(command[i]);
buffer[j] = '\0';
if(strlen(buffer) > 0)
{
(*argv)[k] = (char *) malloc(sizeof(char) * (strlen(buffer) + 1));
strcpy((*argv)[k], buffer);
k++;
}
}
}
}
/* This function will re-initialize the provided arguments and counters. */
void prepare_command(int * count, char *** argv)
{
int i;
for(i = 0; i < *count; i++)
{
(*argv)[i] = NULL;
free((*argv)[i]);
}
*count = 0;
free(*argv);
*argv = NULL;
}
Main
void main(void)
{
char ** arguments, * command;
int count, i;
boolean end = False; // Assume I created an enum for boolean {False, True}
/* Some initialization here. */
count = 0;
arguments = NULL;
do
{
gets(command);
count = word_count(command); /* This will return the number of strings inside the command */
split_command(count, &arguments, command); /* This will allocate an array. */
/* When I try to display something from here, some values are garbage and some are from the previous allocation... */
for(i = 0; i < count; i++)
printf("%s\n", arguments[i]);
prepare_command(&count, &arguments);
}while(!end);
}
PS: I know strtok and I just don't want to use it, and I don't have strtok_r inside any of my libraries here. So I created my own function to take care of something similar to that.
This might be a long post, but I would like you to help me guys... Thanks!
Will have to edit this post if necessary.
Thank you, hope you shed some light to me. :3 :)
Here is a code snippet that I am using:
int parse_args(char** argv, char* data) {
char c;
int argc = 0;
if (argv)
*argv = data;
int quoteopen = 0;
int waitingnextarg = 1;
for (;(c = *data); data++) {
switch(c) {
case '\n':
case '\t':
case ' ':
if (!quoteopen) {
if (argv)
*data = 0;
waitingnextarg = 1;
}
break;
case '"':
if (argv)
*data = 0;
if (quoteopen) {
waitingnextarg = 1;
}
quoteopen ^= 1;
break;
default:
if (waitingnextarg) {
waitingnextarg = 0;
if (argv)
argv[argc] = data;
argc++;
}
break;
}
}
return argc;
}
call with
int argc = parse_args(0, input);
char* argv[argc+1];
parse_args(argv, input);
Careful: changes the input string. This does not deal with any memory allocations, but only uses preallocated memory. If called with argv == NULL it only counts and returns argc, if called with a valid pointer argv it will change the input string and populate argv.
If you need to preserve a copy of the input string call with
int argc = parse_args(0, input);
char input_copy[strlen(input) +1];
memcpy(input_copy, input, strlen(input) +1);
char* argv[argc+1];
parse_args(argv, input_copy);

Resources