I'm attempting to convert command-line arguments into a single char* or "c-string" reference, however it seems my code is breaking. There aren't any compiler warnings, so I'm a bit stuck at this point
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv) {
if (argc < 2) {
printf("usage: program <arguments>");
return 0;
}
char* string = "";
for (int i = 1; i < argc; i++) {
strcat(string, argv[i]);
}
printf("%s", string);
printf("\n");
return 0;
}
Compiling with:
gcc program.c -Wall -std=c99 -o prog
Doesn't seem to throw any warnings, so where could I be going wrong?
Edit:
Updates code to this point:
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv) {
if (argc == 0) {
printf("usage: program <arguments>");
return 1;
}
int tot = 0;
for (int i = 1; i < argc; i++) {
tot += strlen(argv[i]);
}
char string[tot + argc]; // total word length
strcat(string, "\0");
for (int i = 1; i < argc; i++) {
strcat(string, argv[i]);
strcat(string, " ");
}
strcat(string, "\0");
printf("%s", string);
printf("\n");
return 0;
}
However a new problem arises, in that it appears to prepend pseudo-random garbage characters to the string. I added this to the catenation loop to look at the output:
for (int w = 0; w < sizeof(argv[i]); w++) {
printf("\t%s%c\n", "char value: ", argv[i][w]);
}
And this was the output:
./prog one two three
char value: o
char value: n
char value: e
char value:
char value: t
char value: w
char value: o
char value:
char value: t
char value: h
char value: r
char value: e
Tëñ¿one two three
So my guess is that the issue lays within the argument not having a proceeding \0 value, but not 100% certain of how to proceed. Would creating a new array of char to append to, then catenating that be appropriate?
You need to count the total space first:
for (int i = 1; i < argc; i++) {
total += strlen(argv[i]);
}
Then allocate space for final string:
string = calloc(1, total+1);
+1 is for null terminator ('\0').
Then you can strcat to string, and remeber to free it when you don't need it anymore.
Here is the full working code (without error checking):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char** argv) {
int total = 0;
int i;
if (argc < 2) {
printf("usage: program <arguments>");
return 0;
}
char *string;
for (i = 1; i < argc; i++) {
total += strlen(argv[i]);
}
string = calloc(1, total+1);
for (i = 1; i < argc; i++) {
strcat(string, argv[i]);
}
printf("%s", string);
printf("\n");
free(string);
return 0;
}
the way you declare string make the memory that string point to can't be modified.
Instead, you can declare string as char array if you know max size needed. And you'd beter do length checking to make sure it's not overrun when you do strcat
char string[1024]; // put the size you needed
Or you can dynamically allocate space. As suggested by #moeCake.
You're attempting to write into a literal string. Two problems:
1) literal strings aren't generally placed in writable memory.
2) the string (character array) is of size zero; there's no room to write in to it.
The quick answer is to allocate a buffer on the heap:
char* string = (char*)malloc(256);
or on the stack:
char string[256];
Ideally you'd avoid picking a constant size like 256. One approach would be to loop over argv twice - once to measure how much space you'll need, and then again to perform the copies.
Related
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.
I have this peace of C Programming code to take multiple literal strings from the user and store each address to each pointer and print out the value
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr[3];
int i = 0;
for (; i < 3; i++) {
printf("ptr_%d: ", i + 1);
fgets(ptr[i], 15, stdin);
ptr[i][strlen(ptr[i]) - 1] = 0;
puts(ptr[i]);
}
return 0;
}
However, only the first one is printed. Here is the output
ptr_1: first line
first line
Segmentation fault
[Program finished]
I want the same result that is produced Here
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr[] = {
"first line",
"second line",
"third line"
};
puts(ptr[0]);
puts(ptr[1]);
puts(ptr[2]);
return 0;
}
output
first line
second line
third line
[Program finished]
Thanks in advance
fgets(ptr[i], 15, stdin);
You've declared an array of three pointers:
char *ptr[3];
But none of those actually point to buffers of memory.
You can either create those buffers automatically:
char ptr[3][15];
Or dynamically with malloc.
char *ptr[3];
for (size_t i = 0; i < 3; i++) {
ptr[i] = malloc(15);
}
If you do this, make sure to free the memory you've allocated.
If you are running gcc (with glibc 2.7 or greater), you can use the m modifier with scanf to allocate memory:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr[3];
for (i = 0; i < 3; i++) {
printf("ptr_%d: ", i + 1);
while (scanf(" %m[^\n]",&ptr[i]) != 1)
printf("Try again: ");
puts(ptr[i]);
}
for (; i < 3; i++)
free(ptr[i]);
return 0;
}
And be sure to free the memory when you are done with it.
You'd probably want to put the scanf section of this code into a function but here is the smallest change to your existing sample that should work.
$ cat allocinput.c
#include <stdio.h>
#include <string.h>
#define MAX_LEN 80
int main(int argc, char *argv[])
{
char c;
char ptr[3][MAX_LEN];
int i = 0;
for (;i<3;i++) {
printf("ptr_%d: ", i + 1);
// could overflow if the user types more than MAX_LEN characters
char *p = ptr[i];
while (scanf("%c", &c) && (p - ptr[i] < MAX_LEN)) {
if (c == '\n') break;
*p++ = c;
*p = 0;
}
puts(ptr[i]);
}
return 0;}
$ gcc -Wall allocinput.c
$ ./a.out
ptr_1: first line
first line
ptr_2: second line
second line
ptr_3: third line
third line
$
P.S. I recommend astyle to clean up the formatting:
$ astyle allocinput.c
Formatted /tmp/overflow/allocinput.c
$ cat allocinput.c
#include <stdio.h>
#include <string.h>
#define MAX_LEN 80
int main(int argc, char *argv[])
{
char c;
char ptr[3][MAX_LEN];
int i = 0;
for (; i<3; i++) {
printf("ptr_%d: ", i + 1);
// could overflow if the user types more than MAX_LEN characters
char *p = ptr[i];
while (scanf("%c", &c) && (p - ptr[i] < MAX_LEN)) {
if (c == '\n') break;
*p++ = c;
*p = 0;
}
puts(ptr[i]);
}
return 0;
}
I am a beginner so if I miss something vital to the code please forgive me haha. I am making a program which gets input from the console that says how many characters are going to be used, the characters (single letters), and then how long you want the password to be. I feel like I am pretty close, but every time I run the program, it seems to generate a random pattern of letters and I can't follow it.
Here is my code, including the main function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
int generatePassword(char* characters[], int i, char s[], int numCharacters, int passwordLength) {
if (i==0) {
printf("%s\n", s);
return 0;
}
for (int j = 0; j < passwordLength; j++) {
strcat(s, characters[j]);
generatePassword(characters, i-1, s, numCharacters, passwordLength);
}
return 0;
}
void homeFunction(char* characters[], int numCharacters, int passwordLength) {
for (int i = 1; i <= numCharacters; i++) {
char s[MAX] = "";
int c = generatePassword(characters, i, s, numCharacters, passwordLength);
}
}
int main (int argc, char *argv[]) {
if (argc < 2) {
printf("ERROR: Program did not execute due to lack of arguments.\n");
return -1;
}
int numCharacters;
numCharacters = atoi(argv[1]);
int passwordLength;
passwordLength = atoi(argv[numCharacters+2]);
for (int i = 0; i < numCharacters; i++) {
if (strlen(argv[i+1]) > 1) {
printf("ERROR: You can only input one character at a time.\n");
return -1;
}
}
if (argv != numCharacters + 3) {
printf("ERROR: Invalid number of arguments.\n");
return -1;
}
char *charArray[numCharacters];
charArray[numCharacters] = (char*)malloc(numCharacters * sizeof(char));
for (int i = 0; i < numCharacters; i++) {
charArray[i] = argv[i+2];
}
homeFunction(charArray, numCharacters, passwordLength);
return 0;
}
In theory, if the user ran the program with "./NAME 2 a b 2" the result should be
a
b
aa
ab
ba
bb
This is my current output. How can I make it look like the output above?
a
ab
abaa
abaab
abaabba
abaabbab
You need to learn the fundamentals of arrays and strings.
Imagine if I run your code as app.exe 99
This is undefined behavior:
numCharacters = atoi(argv[1]);
int passwordLength;
passwordLength = atoi(argv[numCharacters+2]);
If argv[1] is say, "99", then numCharacters will be 99.
Then passwordLength will be assigned the atoi conversion of argv[101]. But there's only two valid elements in argv: argv[0], which is the executable path, and argv[1], which is "99". argv[2] and up is random memory that's not yours to look at.
This is also wrong:
char *charArray[numCharacters];
charArray[numCharacters] = (char*)malloc(MAX * sizeof(char));
You are allocating an array of (string) pointers, then assigning to an index one past the valid range of the array.
I've got a block of strings, say "aaa\0bbbb\0ccccccc\0"
and I want to turn them into an array of strings.
I've tried to do so using the following code:
void parsePath(char* pathString){
char *pathS = malloc(strlen(pathString));
strcpy(pathS, pathString);
printf(1,"33333\n");
pathCount = 0;
int i,charIndex;
printf(1,"44444\n");
for(i=0; i<strlen(pathString) ; i++){
if(pathS[i]=='\0')
{
char* ith = malloc(charIndex);
strcpy(ith,pathS+i-charIndex);
printf(1,"parsed string %s\n",ith);
exportPathList[pathCount] = ith;
pathCount++;
charIndex=0;
}
else{
charIndex++;
}
}
return;
}
exportPathList is a global variable defined earlier in the code by
char* exportPathList[32];
when using that function exportPathList[i] contains garbage.
What am I doing wrong?
The answer to this SO question:
Parse string into argv/argc
deals with a similar issue, you might have a look.
You need to know how many strings are there or agree for an "end of strings". The simplest would be to have an empty string at the end:
aaa\0bbbb\0ccccccc\0\0
^^
P.S. is this homework?
First of all, since your strings are delimited by a null char, '\0', strlen will only report the size of the string up to the first '\0'. strcpy will copy until the first null character as well.
Further, you cannot know where the input string ends with this information. You either need to pass in the whole size or, for example, end the input with double null characters:
#include <stdio.h>
#include <string.h>
void parsePath(const char* pathString){
char buf[256]; // some limit
while (1) {
strcpy(buf, pathString);
pathString+=strlen(buf) + 1;
if (strlen(buf) == 0)
break;
printf("%s\n", buf);
}
}
int main()
{
const char *str = "aaa\0bbbb\0ccccccc\0\0";
parsePath(str);
return 0;
}
And you need some realloc's to actually create the array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 16
char* exportPathList[MAXSIZE] = {0};
size_t pathCount = 0;
void parsePath(char* pathString){
char *ptop, *pend;
ptop=pend=pathString;
while(*ptop){
while(*pend)++pend;
exportPathList[pathCount++]=strdup(ptop);
pend=ptop=pend+1;
}
}
int main(){
char textBlock[]= "aaa\0bbbb\0ccccccc\0";
//size_t size = sizeof(textBlock)/sizeof(char);
int i;
parsePath(textBlock);
for(i=0;i<pathCount;++i)
printf("%s\n", exportPathList[i]);
return 0;
}
The solution I've implemented was indeed adding double '\0' at the end of the string and using that in order to calculate the number of strings.
My new implementation (paths is the number of strings):
void parsePath(char* pathString,int paths){
int i=0;
while (i<paths) {
exportPathList[i] = malloc(strlen(pathString)+1);
strcpy(exportPathList[i], pathString);
pathString+=strlen(pathString);
i++;
}
}
I'd like to thank everyone that contributed.
My Implementation looks like this -> it follows the idea of argv and argc in a main funtion:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char **args = (char**)malloc(100*sizeof(char));
char buff[100], input_string[100], letter;
for(int i = 0; i < 100; i++){
buff[i] = '\0';
input_string[i] = '\0';
}
for(int i = 0; (letter = getchar())!='\n'; i++){
input_string[i] = letter;
}
int args_num = 0;
for(int i = 0, j = 0; i < 100;i++){
if((input_string[i] == ' ')||(input_string[i]=='\0')){
//reset j = 0
j = 0;
args[args_num] = malloc(strlen(buff+1));
strcpy(args[args_num++],buff);
for(int i = 0; i < 100; i++)buff[i] = '\0';
}else buff[j++] = input_string[i];
}
for(int i = 0; i < args_num; i++){
printf("%s ",args[i]);
}
}
-> Every single word in your string can then be accessed with args[i]
I'm having trouble with comparing strings in C. Firstly, I need to find the length of each string from command-line arguments, and then compare them as well as printing the biggest one.
So far, it's just printing the length of each typed string. I need to compare them according to length, not alphabetic order.
I don't understand why is it now working and what I should do fix it? Thank you!
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i, length;
for(i = 0; i<argc; i++)
{
length = strlen(argv[i]);
printf("%s %d\n", argv[i], length);
if(strlen(argv[i]) < strlen(argv[i+1]))
{
printf("%s is the biggest \n", argv[i+1]);
}
else
{
printf("%s is the biggest \n", argv[i]);
}
}
return 0;
}
There are a few problems with your code.
First of all, argv[i+1] is an illegal operation if you're doing i < argc in the for. You need to change i < argc to i < argc - 1 in the for.
Secondly, you are probably not comparing the strings you want. argv[0] is the string representing the path of your program; the first argument passed to your program is argv[1]. Therefore, you need to change the i = 0 in the for to i = 1.
Finally, if you only want the biggest string, you should not do any printing in the for loop. Rather, you should create two variables like max_length and max_length_idx where you would store the length and index of the largest string found so far. Then, after the for loop, your program would print out the string argv[max_length_idx].
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i, max_length, max_index;
max_index = 0;
max_length = strlen(argv[0]);
for(i = 1; i < argc; i++)
{
if(strlen(argv[i]) > max_length)
{
max_length = strlen(argv[i]);
max_index = i;
}
}
printf("The longest is: %s with length equal: %d\n", argv[max_index], max_length);
return 0;
}
This will not segfault ...
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i, length;
for(i = 0; i<argc - 1; i++)
{
length = strlen(argv[i]);
printf("%s %d\n", argv[i], length);
if(strlen(argv[i]) < strlen(argv[i+1]))
{
printf("%s is the biggest \n", argv[i+1]);
}
else
{
printf("%s is the biggest \n", argv[i]);
}
}
return 0;
}