How can I concatenate all the values in argv to one string using snprintf?
if i pass in values like ./prog val1 val2 val3 val4
my string
char all_values[MAX_LEN] should be "val1 val2 val3 val4"
How can I do this efficiently using snprintf()?
#include <stdio.h>
#define MAX_LEN 16
int main(int ac, char **av) {
char buffer[MAX_LEN];
buffer[0] = 0;
int offset = 0;
while(av++,--ac) {
int toWrite = MAX_LEN-offset;
int written = snprintf(buffer+offset, toWrite, "%s ", *av);
if(toWrite < written) {
break;
}
offset += written;
}
printf("%s\n", buffer);
}
If you to want make a print of N arguments, you can do
int i = 1 ; // first parameter is a program name
while(i < argc )
{
printf("%s",argv[1]);
i++;
}
But if you want to use a string in other processor,you would really concatenate then. Maybe with:
char* string_result;
int i = 1;
int size_total = 0;
bool space_needed = false;
while(i < argc) { // argc contain the number of arguments
size_total += strlen(argv[i])+1; //+1 for a new space each time.
i++;
}
if(i > 2) {
space_needed = true;
size_total -= 1; //no need for space at end of string
}
string_result = (char*)malloc((size_total+1)*sizeof(char));
string_result[0] = 0 ; // redundant?
i = 1;
while(i < argc) {
strcat(string_result,argv[i]); // caution to concatenate argv string, memory of OS.
if(space_needed && (i+1) < argc)
strcat(string_result, " "); //space so it looks better.
i++;
}
//free pointer when done using it.
free(string_result);
Assuming sizoeof(char)==1, untested code!
#include <stdlib.h>
#include <string.h>
int i ;
int size_total = 0;
size_t *lens=(size_t *)malloc((argc)*sizeof(size_t));
for (i=1;i < argc; i++) {
lens[i]=strlen(argv[i]);
size_total += lens[i]+1;
}
concatinated = (char*)malloc(size_total);
char *start=concatinated;
for (i=1;i < argc; i++) {
memcpy(start, argv[i], lens[i]);
start+=lens[i];
*start=' ';
start++;
}
start--;
*start=0;
free(lens);
Related
I am attempting to write the substitution program here https://cs50.harvard.edu/x/2022/psets/2/substitution/
here is my code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
int main(int argc, string argv[1])
{
if (argc > 2 || argc < 2){
printf("Plz 1 word in command \n");
return 1;
}
int sum = 0;
string arg1 = argv[1];
//test
for (int i = 0; i < strlen(arg1); i++){
if (isalpha(arg1[i]) == 0){
printf("plz only alphabet character \n");
return 1;
}}
// convert all key to upper
for (int i = 0; i < strlen(arg1); i++){
arg1[i] = toupper(arg1[i]);
}
for (int i = 0; i < strlen(arg1); i++){
sum = sum + (int)(arg1[i]);
}
if (strlen(arg1) != 26){
printf("Plz input 26 char \n");
return 1;
} else if (sum != 2015){printf("no oveerlapping letter plz \n");
return 1; }
//test finish
string al = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string pt = get_string("plaintext: ");
char pt1[strlen(pt)];
char cp[strlen(pt)];
// all plain text to upper
for (int i = 0; i < strlen(pt); i++){
pt1[i]=toupper(pt[i]);
}
//scan
for (int a = 0; a < strlen(pt); a++){
char b = pt1[a];
for (int i = 0; i < strlen(al); i++){
if ( al[i] == b){
cp[a] = arg1[i];
break;
} else {
cp[a] = b;
}
}
//case preserve
if (islower(pt[a])){
cp[a] = tolower(cp[a]);
}}
printf("ciphertext: %s \n", cp);
return 0;
}
when i type in the key YTNSHKVEFXRBAUQZCLWDMIPGJO and then type "hello!1 lmao" as plaintext, here is what i receive
substitution/ $ ./substitution YTNSHKVEFXRBAUQZCLWDMIPGJO
plaintext: hello!1 lmao
ciphertext: ehbbq!1 bayq�
it should only show ehbbq!1 bayq but it is showing more letter than i intended,
there might be other letter or simbol after "bayq", can someone explain to me what is going on and why there are additional text in my output?
You need a null terminatig character (usually it is character having integer value 0) to terminate the string
size_t a;
for (a = 0; a < strlen(pt); a++)
{
char b = pt1[a];
for (int i = 0; i < strlen(al); i++)
{
if ( al[i] == b)
{
cp[a] = arg1[i];
break;
} else {
cp[a] = b;
}
}
//case preserve
if (islower((unsigned char)pt[a]))
{
cp[a] = tolower((unsigned char)cp[a]);
}
}
cp[a] = 0;
you need to pass unsigned char to functions like tolower. I did not analyze the logic of your code as it is your home work.
Also cp is too short, it has to be char cp[strlen(pt) + 1];
Your char arrays as declared are too short to handle copies of the data, due to the need for a null-terminator att the end.
char pt1[strlen(pt)];
char cp[strlen(pt)];
Rather you need to do:
char pt1[strlen(pt) + 1];
char cp[strlen(pt) + 1];
However, the other approach would be to simply use strdup to dynamically allocate sufficient storage and copy the data.
char pt1 = strdup(pt);
char cp = strdup(pt);
Of course, any function that returns dynamically allocated memory (likely including cs50's get_string) means you should remember to free that memory. And ensure it actually succeeded.
I'm trying to write my own concatenate program. What I'm doing is getting two strings as input from argv, creating a third empty character array that holds the length of argv[1] + argv[2], and then use two for loops to insert the characters from each argv string into the third string.
My first for loop seems to be working fine buy my second for loop isn't doing anything. Any ideas?
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *string1 = argv[1];
char *string2 = argv[2];
int string1Len = strnlen(string1, 50);
int string2Len = strnlen(string2, 50);
char string3[string1Len + string2Len + 1];
for (int i = 0; i <= string1Len; i++)
{
string3[i] = string1[i];
}
for(int i = (string1Len + 1); i <= (string1Len + string2Len); i++)
{
string3[i] = string2[i];
}
string3[string1Len + string2Len + 1] = '\0';
printf("%s %d %d\n", string3, string1Len, string2Len);
return 0;
}
You can simplify (and optimize) it by using the memcpy function
int main(int argc, char **argv) {
if (argc < 3) return 1;
const char *string1 = argv[0];
const char *string2 = argv[1];
const size_t string1Len = strlen(string1);
const size_t string2Len = strlen(string2);
char *string3 = malloc((string1Len + string2Len + 1) * sizeof(*string3));
memcpy(string3, string1, string1Len * sizeof(*string1));
memcpy(string3 + string1Len, string2, (string2Len + 1) * sizeof(*string2));
printf("%s %zu %zu", string3, string1Len, string2Len);
free(string3);
return 0;
}
And as the others said, pay attention to the nul terminator
Your second for loop "did nothing" because the first one worked up to the \0 character and included it in string3, so it's better to set the condition that the for loop works up to that character
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *string1 = argv[1];
char *string2 = argv[2];
int string1Len = strlen(string1);
int string2Len = strlen(string2);
int i;
char string3[string1Len + string2Len +1];
for (i = 0; string1[i]!='\0'; i++)
{
string3[i] = string1[i];
}
string3[i]=' '; //with space
++i;
for(int j = 0; string2[j]!='\0'; j++)
{
string3[i] = string2[j];
i++;
}
string3[string1Len + string2Len + 1] = '\0';
printf("%s %d %d\n", string3, string1Len, string2Len);
return 0;
}
There are two main issues in your code. Your first for loop copies the nul terminator from string1; so, anything you then add to your string3 after that will simply be ignored by functions like printf, because they see that nul as marking the end of the string.
In your second for loop, you have the same problem and, more critically, the i index you use is not valid for string2, as you have added the length of string1 to it.
Also, note that arrays in C start at zero, so you shouldn't add the 1 to the position of the final nul terminator.
Here's the "quick fix" for your current code:
for (int i = 0; i < string1Len; i++) { // Use "<" in place of "<=" or we copy the null terminator
string3[i] = string1[i];
}
for (int i = 0; i < string2Len; i++) { // Start "i" at 0 for valid "string2" index ...
string3[i + string1Len] = string2[i]; // ... and add "string1Len" for the destination index
}
string3[string1Len + string2Len] = '\0'; // Arrays start at ZERO, so don't add 1 for "nul" terminator position
However, there are some other points and possible improvements. Note that the strnlen function returns a size_t type, so you would be better off using that for your indexes. Also, as you know that the i index at the end of the first loop will still be valid for the next character, you can re-use that in the second loop (so long as you have declared it outside the first loop), and you can use a second index for the source string.
Also, as pointed out by chqrlie, you really should check that you have sufficient source data in the argv array.
Here's a version of your program with those additional changes:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
if (argc < 3) {
// Error-handling code
return 1;
}
char* string1 = argv[1];
char* string2 = argv[2];
size_t string1Len = strnlen(string1, 50);
size_t string2Len = strnlen(string2, 50);
size_t i, j;
char string3[string1Len + string2Len + 1];
for (i = 0; i < string1Len; i++) {
string3[i] = string1[i];
}
for (j = 0; j < string2Len; j++, i++) {
string3[i] = string2[j];
}
string3[i] = '\0';
printf("%s %zu %zu\n", string3, string1Len, string2Len); // "%zu" for "size_t"
return 0;
}
The problem in your second loop is that i starts beyond the beginning of the second string. However, if all you are trying to do is to write you own custom (max 50 chars) concatenate program, all you need to do is to printf the arguments one after the other and printf can help limit:
#include <stdio.h>
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; ++i) printf("%.50s", argv[i]);
printf("\n");
return 0;
}
There is no need to copy in memory to a VLA and print.
If you need to create a function that concatenates, you better use malloc - as you can't safely return a VLA: (note, the following example will not limit to 50 chars):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concat(int argc, char* argv[]) {
size_t totalsize = 1;
for (int i = 0; i < argc; ++i) totalsize += strlen(argv[i]);
char* ret = malloc(totalsize);
if (!ret) exit(1);
if (!argc) *ret = 0;
char* dst = ret;
for (int i = 0; i < argc; ++i) {
char* src = argv[i];
while (*dst++ = *src++); /* Copy also the \0 */
--dst;
}
return ret;
}
int main(int argc, char *argv[])
{
char* str = concat(argc - 1, argv + 1); /* Skip the program name */
printf("%s\n", str);
free(str);
return 0;
}
Note that the above examples will concatenate any number of strings.
The index values in both loops are incorrect:
you should stop the first loop when i == string1Len, hence the test should be:
for (int i = 0; i < string1Len; i++)
you should use add string1Len to the index into the destination string so bytes from the second string are appended to those of the first string:
for (int i = 0; i < string2Len; i++) {
string3[string1Len + i] = string2[i];
}
the index for the null terminator is string1Len + string2Len, adding 1 is incorrect as indexing is zero based in C:
string3[string1Len + string2Len] = '\0';
you should test the actual number of arguments provided to the program to avoid undefined behavior if some are missing.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "missing arguments\n");
return 1;
}
char *string1 = argv[1];
char *string2 = argv[2];
int string1Len = strnlen(string1, 50);
int string2Len = strnlen(string2, 50);
char string3[string1Len + string2Len + 1];
for (int i = 0; i < string1Len; i++) {
string3[i] = string1[i];
}
for (int i = 0; i < string2Len; i++) {
string3[string1Len + i] = string2[i];
}
string3[string1Len + string2Len] = '\0';
printf("%s %d %d\n", string3, string1Len, string2Len);
return 0;
}
The program reads a file which includes one word in every line.After reading random word put random word in a pointer and return the pointer .in main function
printf("%s",func("example.txt",str)) it prints different string when the program run.I want to do this in 2d array(20*20) like table,but i could not imagine how to do this.When i print the the function in internal loop,it give me the same word in every loop step.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char *word(char *file, char *str);
int main() {
char *str ;
int i, j;
str = (char *)malloc(20);
srand(time(NULL));
char *puzzle[20][20];
for (i = 0; i < 20; i++) {
for (j = 0; j < 20; j++) {
puzzle[i][j] = word("words.txt", str);
}
}
for (i = 0; i < 20; i++) {
for (j = 0; j < 20; j++) {
printf("%s ", puzzle[i][j]);
}
printf("\n");
}
}
char *word(char *file, char *str) {
int end, loop, line;
FILE *fd = fopen(file, "r");
if (fd == NULL) {
printf("Failed to open file\n");
return (NULL);
}
srand(time(NULL));
line = rand() % 100 + 1;
for (end = loop = 0; loop < line; ++loop) {
if (0 == fgets(str, 20, fd)) {
end = 1;
break;
}
}
if (!end)
return (char *)str;
fclose(fd);
free(str);
}
I do not have your words.txt file, so I've created some random strings below.
And a note:
Because your nested loop is in the main, your code opens the file in the sub function and returns w/o closing it; then returns to the sub and reopens, and again, and again... It's always better to read at once and close the file before returning from the sub.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char **word(int countString, int maxChars) {
int i;
int j;
int k;
// allocate memory for pointers that are pointing to each string
char **arrStr = malloc(countString * sizeof(char *));
// srand(time(NULL));
for (i = 0; i < countString; i++) {
// create a random string with a length of 'k'
// say, 5 <= k <= maxChars
// that (+ 1) is for the string terminating character '\0'
k = (rand() % (maxChars - 5)) + 5 + 1;
// allocate memory for string
arrStr[i] = malloc(k * sizeof(char));
for (j = 0; j < k - 1; j++) {
*(arrStr[i] + j) = rand() % 26 + 'A';
}
*(arrStr[i] + j) = '\0';
}
return arrStr;
}
int main() {
int countString = 10;
int maxChars = 20;
char **arrStr = NULL;
int i;
arrStr = word(countString, maxChars);
for (i = 0; i < 10; i++) {
printf("%s\n", *(arrStr + i));
}
// do not forget to free the strings
// and then the string pointers (array)
return 0;
}
I'm working on a program that takes command line arguments and splits them in half and then orders them in lexicographical order.
For example:
hello, world!
would turn into:
he
ld!
llo
wor
I have a main method that reads through the arguments, a function that splits the arguments, and finally a function that is supposed to order the halves in lexicographical order. I can't get this to run properly because of argument type errors in the lexicographicalSort method and an incompatible pointer type in the main method. I'm having issues to correct these syntax errors, how exactly would I correct them? Also, is there anything here that would cause logical errors? This is what I have so far:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int splitString(char arg[], int n)
{
int len = strlen(arg);
int len1 = len/2;
int len2 = len - len1; // Compensate for possible odd length
char *s1 = malloc(len1 + 1); // one for the null terminator
memcpy(s1, arg, len1);
s1[len1] = '\0';
char *s2 = malloc(len2 + 1); // one for the null terminator
memcpy(s2, arg + len1, len2);
s2[len2] = '\0';
printf("%s\n", s1);
printf("%s\n", s2);
free(s1);
free(s2);
return 0;
}
int lexicographicalSort(char *arg[], int n)
{
char temp[50];
for(int i = 0; i < n; ++i)
scanf("%s[^\n]",arg[i]);
for(int i = 0; i < n - 1; ++i)
for(int j = i + 1; j < n ; ++j)
{
if(strcmp(arg[i], arg[j]) > 0)
{
strcpy(temp, arg[i]);
strcpy(arg[i], arg[j]);
strcpy(arg[j], temp);
}
}
for(int i = 0; i < n; ++i)
{
puts(arg[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
int j = 1;
int k = strlen(argv[i]);
splitString(argv[i], j);
lexicographicalSort(argv[i], j);
}
}
}
Basic scheme is simple. Make an array of tuples {start_pointer, length}. Do some programming on args to split the args. Fill in the array as appropriate. Make sorting with qsort, or any other sort of your choise.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char *s = "hello, world! . hello.....";
char *pc;
int i, n, nargs;
struct pp{
char *p;
int l;
};
struct pp args[10], hargs[20];
struct pp *pargs;
int cmp(const void * v0, const void * v1) {
struct pp *pv0 = v0, *pv1 = v1;
return strncmp(pv0->p, pv1->p, pv0->l);
}
int main(void)
{
for(pc = s, i = 0; *pc; ++i){
sscanf(pc, "%*[^ ]%n", &n);
if(n > 0){
args[i].p = pc;
args[i].l = n;
}
for(pc += n, n = 0; isspace(*pc); ++pc);
}
for(nargs = i, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, args[i].l, args[i].p);
putchar('\n');
for(i = 0, pargs = hargs; i < nargs; ++i){
if(args[i].l == 1){
pargs->p = args[i].p;
pargs->l = 1;
pargs = pargs + 1;
}else {
pargs->p = args[i].p;
pargs->l = args[i].l / 2;
pargs = pargs + 1;
pargs->p = args[i].p + args[i].l / 2;
pargs->l = args[i].l - args[i].l / 2;
pargs = pargs + 1;
}
}
putchar('\n');
for(nargs = pargs - hargs, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
qsort(hargs, nargs, sizeof(struct pp), cmp);
putchar('\n');
for(i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
return 0;
}
https://rextester.com/GSH22767
Upon splitting a C string, one needs one extra char to store extra null-terminator. There is one answer that bypasses this by storing the length. For completeness, this is closer to your original intention: allocating enough space to copy the programmes arguments. It probably works slower, but one is free to use the strings elsewhere in the programme.
#include <stdlib.h> /* malloc free EXIT qsort */
#include <stdio.h> /* fprintf */
#include <string.h> /* strlen memcpy */
#include <errno.h> /* errno */
static int strcompare(const void *a, const void *b) {
const char *a_str = *(const char *const*)a, *b_str = *(const char *const*)b;
return strcmp(a_str, b_str);
}
int main(int argc, char **argv) {
char *spacev = 0, **listv = 0;
size_t spacec = 0, listc = 0;
int is_done = 0;
do { /* "Try." */
int i;
char *sv;
size_t j;
/* This requires argc > 1. */
if(argc <= 1) { errno = EDOM; break; }
/* Allocate maximum space. */
for(i = 1; i < argc; i++) spacec += strlen(argv[i]) + 2;
if(!(spacev = malloc(spacec)) || !(listv = malloc(argc * 2))) break;
sv = spacev;
/* Copy and split the arguments. */
for(i = 1; i < argc; i++) {
const char *const word = argv[i];
const size_t word_len = strlen(word),
w0_len = word_len / 2, w1_len = word_len - w0_len;
if(w0_len) {
listv[listc++] = sv;
memcpy(sv, word, w0_len);
sv += w0_len;
*(sv++) = '\0';
}
if(w1_len) {
listv[listc++] = sv;
memcpy(sv, word + w0_len, w1_len);
sv += w1_len;
*(sv++) = '\0';
}
}
/* Sort. */
qsort(listv, listc, sizeof listv, &strcompare);
for(j = 0; j < listc; j++) printf("%s\n", listv[j]);
is_done = 1;
} while(0); if(!is_done) {
perror("split");
} {
free(spacev);
free(listv);
}
return is_done ? EXIT_SUCCESS : EXIT_FAILURE;
}
It is simpler than your original; instead of allocating each string individually, it counts the maximum number of chars needed (plus two for two null terminators) and allocates the block all at once (space.) The pointers to the new list also need allocating, the maximum is 2 * argc. Once you copy and modify the argument list, one has an actual array of strings that one can qsort.
I know that getline is C++ standard but I need to read a line of digits:
123856
and save it to an array. But how to do this without spaces between given (as input) digits? I want a user input to be:
123856 (with no spaces) and then save it to an array (n element array) and after that, I want my array to look like this:
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 8;
array[4] = 5;
array[5] = 6;
But how to make it in C, without a getline?
This is NOT what I want:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
int t[4];
int i;
for(i=0; i<4; i++)
scanf("%d", &t[i]);
for(i=0; i<4; i++)
printf("%d\n", t[i]);
return 0;
}
If I understood you correct, the following should do it:
read the whole line
loop through the string as long as you get digits or the string ends
for every digit, place it's value in your array and increase the index by 1
while( ( c = getchar()) != EOF && c != '\n' && i < max ) {
/* If desired, add check for value outside of 0-9 */
array[ i++ ] = c - '0';
...
}
char arr[] = "1234567";
int intarr[10];
int count = 0;
for (char* ptr = arr; *ptr; ptr++) {
intarr[count] = *ptr - '0';
count++;
}
try this
#include <stdio.h>
#include <string.h>
main (int argc, char *argv[])
{
FILE *f;
int i=0;
int j=0;
char output[100];
char* output1[100];
char string[100];
char delims1[] = " ";
char delims2[] = "*";
char* result = NULL;
char* result3 = NULL;
int num;
//for (j=0; j<2; j++)
//{
//printf("%s",delims9[6]);
//}
f = fopen("text.txt","r");
//
while( fgets(string,sizeof(string),f) )
{
result = strtok( string, delims1 );
while( result != NULL )
{
output1[i]=result;
printf("%s\n",output1[i]);
result = strtok( NULL, delims1 );
i++;
}
for (num = 0; num < 100; i++ ) //
{ // Error On this array
printf("%s\n", output1[i]); //
} //
}
printf("\n%d",i/3+1);
return 0 ;
}
Ok, without using any string.
int digits = 123856;
int numofdigits = 1 + floor(log10(digits));
int digits_arr[numofdigits];
int i;
for(i = numofdigits-1; i >= 0; i--) {
digits_arr[i] = (int)floor(digits / pow(10, i)) % 10;
}
Try the below link... Same question asked here and get solution....
convert an integer number into an array
char * convertNumberIntoArray(unsigned int number) {
unsigned int length = (int)(log10((float)number)) + 1;
char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
do {
*curr++ = number % 10;
number /= 10;
} while (number != 0);
return arr;
}