C中的sprintf给出了错误的输出

时间:2016-02-21 09:07:46

标签: c printf

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

#define MAX_STRING  20

char *getFirstName() {
    char firstName[MAX_STRING];
    printf("Please enter your first name: ");
    gets(firstName);
    return (firstName);
}

char *getLastName() {
    char lastName[MAX_STRING];

    printf("Please enter your last name: ");
    gets(lastName);
    return (lastName);
}

char *getNickName() {
    char nickName[MAX_STRING];
    printf("Please enter your nick name: ");
    gets(nickName);
    return (nickName);
}

char *getCompleteName(const char *firstName,
                      const char *lastName,
                      const char *nickName) {
    char *completeName;
    sprintf(completeName, "%s \"%s\" %s", firstName, nickName, lastName);
    return (completeName);
}

int main() {
    char *firstName;
    char *lastName;
    char *nickName;
    char *completeName;

    firstName   = getFirstName();
    lastName    = getLastName();
    nickName    = getNickName();

    completeName = getCompleteName(firstName, lastName, nickName);
    printf("Hello %s.\n", completeName);
    return (EXIT_SUCCESS);
}

代码有什么问题。它始终在所有三个可变量firstNamelastNamenickName中打印昵称。

输出: Output]

必须显示完整的名称。我认为错误在getCompleteName函数中。

6 个答案:

答案 0 :(得分:2)

在函数getCompleteName中,在将内容编入其中之前,必须为completeName分配内存:

char *getCompleteName(const char *firstName, 
                      const char *lastName,
                      const char *nickName)
{
    size_t size = strlen(firstName) + strlen(lastName) + strlen(nickName) + 5;
    char *completeName = malloc(size);
    if (completeName) {
        snprintf(completeName, size, "%s \"%s\" %s", firstName, nickName, lastName);
    }
    return completeName;
}

注意:

  • 调用函数将负责释放内存。这种分配方案实用但容易出错,已知会在草率实现中导致内存泄漏。
  • 其余代码也存在同样的问题:指针必须指向调用函数中已分配的内存,静态数组或本地数组。
  • 您不能使用gets(),不能安全使用。使用fgets()并删除尾随换行符。

答案 1 :(得分:1)

char* completeName;
sprintf(completeName,"%s \"%s\" %s",firstName,nickName,lastName);

completeName指向哪里?由于使用了不确定的值,这会调用未定义的行为

您应该提供静态存储,例如与

static char completeName[128];

下一个问题是自动变量,例如函数返回时超出范围。您应该使数组静态以避免这种情况。

答案 2 :(得分:1)

1)你不能在堆栈上使用数组 - 也许这可能会更好

  #include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include<signal.h>
#include<stdint.h>
#include<string.h>
#include<time.h>


void formatted_time(char* sender_name, char* receiver_name, char output[]);
void formatted_time(  char* sender_name ,  char* receiver_name, char output[])
{
  struct timeval tv;
  time_t nowtime;
  struct tm *nowtm;
char tmbuf[80];
  gettimeofday(&tv, NULL);
  nowtime = tv.tv_sec;
  nowtm = localtime(&nowtime);
  strftime(tmbuf,80 , "%Y-%m-%d %H:%M:%S",
            nowtm);
  sprintf(output, "%s: Time at %s is %s.", receiver_name, sender_name,  tmbuf);
}

int main(int argc, char** argv)
{
     char* parent="Parent";
     char* child1="Child1";
     char* child2="Child2";
    char result[80];
    char buffer[80];
    int firstchild,secondchild,read1,read2,read3;
    firstchild=fork();
        int mypipe[2];
    int mypipe2[2];
    int mypipe3[2];

        if(pipe(mypipe) == -1) {
          perror("Pipe failed");
          exit(1);
        }

        if(firstchild == 0)            //first child
        {
         close(mypipe[1]);    //Closing  the output  of pipe
    sleep(3);
    read1=read(mypipe[0],buffer,sizeof(buffer));    
     printf("%s\n",buffer);



        }else{
    secondchild=fork();        //Creating second child

        if(secondchild == 0)            //2nd child
        {

        sleep(6);


        }else{            //Parent
    close(mypipe[0]);     //Closing the input of pipe
    formatted_time(parent,child1,result);   
    write(mypipe[1],result,strlen(result)+1);
    //printf("%s\n",result);

2)使用它

 void getDetail(const char * const prompt, char *detail, int maxSize)
 {
    printf("%s:", prompt);
    fflush(stdout); // Gives the user a chance to set it
    if (fgets(detail, maxSize, stdin) == NULL) {
       detail[0] = 0; // EOF - Empty string
    }
    else
    {
       // Strip off new line
       size_t l = strlen(detail);
       if (detail[l - 1] == '\n') detail[l - 1] = 0;
    }

 }

3)现在制作完整的名字

char firstName[MAX_SIZE];
getDetail("Please enter you first name", firstName, MAX_SIZE);


... ditto for the others

...如果你希望把它放到一个函数中传递给它。但在示例中似乎不值得

4)打印完整名称

char completeName{MAX_SIZE * 3 + 10]; // Cannot be bothered to work out the exta but that will be enough
sprintf(completeName,"%s \"%s\" %s",firstName,nickName,lastName);

答案 3 :(得分:1)

我建议使用char数组并将它们作为参数传递给您的函数。如果char firstName[MAX_STRING];终止,则本地数组getFirstName超出范围。在getFirstName终止并且指向变量的指针未定义行为后,此变量不再可访问。

#include <stdio.h>

#define MAX_STRING 10

void getFirstName( char *firstName )
{
    printf("Please enter your first name: ");
    fflush( stdout );
    fgets( firstName, MAX_STRING, stdin );
}

void getLastName( char *lastName )
{
  printf("Please enter your last name: ");
  fflush( stdout );
  fgets( lastName, MAX_STRING, stdin );
}

void getNickName( char *nickName )
{
    printf("Please enter your nick name: ");
    fflush( stdout );
    fgets( nickName, MAX_STRING, stdin );
}

void getCompleteName (
         char*          completeName,
         const char*    firstName,
         const char*    lastName,
         const char*    nickName)
{
  sprintf(completeName,"%s \"%s\" %s",firstName,nickName,lastName);
}

int main ()
{
  char firstName[MAX_STRING];
  char lastName[MAX_STRING];
  char nickName[MAX_STRING];
  char completeName[MAX_STRING*3+10];

  getFirstName( firstName  );
  getLastName( lastName );
  getNickName( nickName );

  getCompleteName( completeName, firstName, lastName, nickName );
  printf("Hello %s.\n",completeName);
  return(EXIT_SUCCESS);
} 

除了fgets使用gets之外,因为fgets会检查要读取的最大字符数(包括最终的空字符) 见How to read from stdin with fgets()?

答案 4 :(得分:0)

指针变量completeName未初始化,导致C标准调用未识别的行为。任何事情都可能发生。

您还尝试从函数中返回数组。它们被转换为指向每个数组中第一个元素的指针,并返回该指针。但由于数组是一个局部变量,所谓的&#34;存储类auto&#34;,它在函数返回时消失。 Rhe记忆可以重复用于其他事情,但指针仍然指向内存中的那个位置。同样,行为未定义。

答案 5 :(得分:0)

使用char和fgets数组代替gets。顺便说一句,您的初始代码会在Ubuntu 15.10和gcc(Ubuntu 5.2.1-22ubuntu2)5.2.1 20151010上产生分段错误。

SK